Merge remote-tracking branch 'remotes/tom-repo/develop' into PhotonQyv-Baseline

This commit is contained in:
PhotonQyv 2017-09-15 19:03:02 +01:00
commit 93c4bb8eb7
22 changed files with 349 additions and 40 deletions

View File

@ -74,17 +74,21 @@ import java.util.Locale;
import java.util.Stack;
import java.util.regex.Matcher;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveInstanceAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveMetaDataAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.UpdateAccountInfoByIDAsyncTask;
import fr.gouv.etalab.mastodon.client.APIResponse;
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.Entities.Version;
import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader;
import fr.gouv.etalab.mastodon.fragments.DisplayAccountsFragment;
import fr.gouv.etalab.mastodon.fragments.DisplayFollowRequestSentFragment;
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.OnRetrieveInstanceInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMetaDataInterface;
import fr.gouv.etalab.mastodon.interfaces.OnUpdateAccountInfoInterface;
import fr.gouv.etalab.mastodon.services.StreamingService;
@ -211,6 +215,7 @@ public class MainActivity extends AppCompatActivity
startService(intent);
}
}
Helper.canPin = false;
Helper.fillMapEmoji(getApplicationContext());
//Here, the user is authenticated
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
@ -565,7 +570,8 @@ public class MainActivity extends AppCompatActivity
}
Helper.switchLayout(MainActivity.this);
// Retrieves instance
new RetrieveInstanceAsyncTask(getApplicationContext(), MainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@ -1095,6 +1101,18 @@ public class MainActivity extends AppCompatActivity
}
}
@Override
public void onRetrieveInstance(APIResponse apiResponse) {
if( apiResponse.getError() != null){
return;
}
if( apiResponse.getInstance() == null || apiResponse.getInstance().getVersion() == null || apiResponse.getInstance().getVersion().trim().length() == 0)
return;
Version currentVersion = new Version(apiResponse.getInstance().getVersion());
Version minVersion = new Version("1.6");
Helper.canPin = (currentVersion.compareTo(minVersion) == 1 || currentVersion.equals(minVersion));
}
/**
* Page Adapter for settings

View File

@ -20,7 +20,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@ -78,6 +77,7 @@ import fr.gouv.etalab.mastodon.asynctasks.RetrieveAccountsAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveRelationshipAsyncTask;
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.Error;
import fr.gouv.etalab.mastodon.client.Entities.Status;
@ -89,9 +89,8 @@ import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveAccountInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsAccountInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRelationshipInterface;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import mastodon.etalab.gouv.fr.mastodon.R;
import fr.gouv.etalab.mastodon.client.Entities.Relationship;
@ -103,7 +102,7 @@ import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor;
* Show account activity class
*/
public class ShowAccountActivity extends AppCompatActivity implements OnPostActionInterface, OnRetrieveAccountInterface, OnRetrieveFeedsAccountInterface, OnRetrieveRelationshipInterface {
public class ShowAccountActivity extends AppCompatActivity implements OnPostActionInterface, OnRetrieveAccountInterface, OnRetrieveFeedsAccountInterface, OnRetrieveRelationshipInterface, OnRetrieveFeedsInterface {
private ImageLoader imageLoader;
@ -120,12 +119,13 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
private String userId;
private static int instanceValue = 0;
private Relationship relationship;
private boolean showMediaOnly;
private boolean showMediaOnly, showPinned;
private ImageView pp_actionBar;
private BroadcastReceiver hide_header;
private boolean isHiddingShowing = false;
private LinearLayout main_header_container;
private ImageView header_edit_profile;
private List<Status> pins;
public enum action{
FOLLOW,
@ -149,6 +149,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
setContentView(R.layout.activity_show_account);
setTitle("");
instanceValue += 1;
pins = new ArrayList<>();
Bundle b = getIntent().getExtras();
account_follow = (FloatingActionButton) findViewById(R.id.account_follow);
account_follow_request = (TextView) findViewById(R.id.account_follow_request);
@ -160,10 +161,12 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
new RetrieveRelationshipAsyncTask(getApplicationContext(), accountId,ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new RetrieveAccountAsyncTask(getApplicationContext(),accountId, ShowAccountActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
}else{
Toast.makeText(this,R.string.toast_error_loading_account,Toast.LENGTH_LONG).show();
}
showMediaOnly = false;
showPinned = false;
imageLoader = ImageLoader.getInstance();
File cacheDir = new File(getCacheDir(), getString(R.string.app_name));
ImageLoaderConfiguration configImg = new ImageLoaderConfiguration.Builder(this)
@ -331,6 +334,9 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_showaccount, menu);
if( !Helper.canPin || !accountId.equals(userId)) {
menu.findItem(R.id.action_show_pinned).setVisible(false);
}
return true;
}
@ -340,6 +346,14 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
case android.R.id.home:
finish();
return true;
case R.id.action_show_pinned:
showPinned = !showPinned;
if( tabLayout.getTabAt(0) != null)
//noinspection ConstantConditions
tabLayout.getTabAt(0).select();
PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
return true;
case R.id.action_show_media:
showMediaOnly = !showMediaOnly;
if( showMediaOnly )
@ -349,7 +363,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
if( tabLayout.getTabAt(0) != null)
//noinspection ConstantConditions
tabLayout.getTabAt(0).select();
PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
return true;
default:
@ -488,7 +502,9 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
tabLayout.getTabAt(1).setText(getString(R.string.following_cnt, account.getFollowing_count()));
//noinspection ConstantConditions
tabLayout.getTabAt(2).setText(getString(R.string.followers_cnt, account.getFollowers_count()));
}
imageLoader.displayImage(account.getAvatar(), account_pp, options);
}
}
@ -503,6 +519,30 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
}
}
@Override
public void onRetrieveFeeds(APIResponse apiResponse, boolean refreshData) {
if( apiResponse.getError() != null){
final SharedPreferences sharedpreferences = getApplicationContext().getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true);
if( show_error_messages)
Toast.makeText(getApplicationContext(), apiResponse.getError().getError(),Toast.LENGTH_LONG).show();
return;
}
pins = apiResponse.getStatuses();
if (pins != null && pins.size() > 0) {
if( pins.get(0).isPinned()) {
for (Status pin : pins) {
this.statuses.add(pin);
}
//noinspection ConstantConditions
tabLayout.getTabAt(3).setText(getString(R.string.pins_cnt, pins.size()));
statusListAdapter.notifyDataSetChanged();
}
}
}
@Override
public void onRetrieveRelationship(Relationship relationship, Error error) {
@ -557,7 +597,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
}
/**
* Pager adapter for the 3 fragments
* Pager adapter for the 4 fragments
*/
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
ScreenSlidePagerAdapter(FragmentManager fm) {
@ -574,6 +614,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
bundle.putString("targetedId", accountId);
bundle.putBoolean("hideHeader",true);
bundle.putBoolean("showMediaOnly",showMediaOnly);
bundle.putBoolean("showPinned",showPinned);
bundle.putString("hideHeaderValue",String.valueOf(instanceValue));
displayStatusFragment.setArguments(bundle);
return displayStatusFragment;

View File

@ -161,7 +161,7 @@ public class ShowConversationActivity extends AppCompatActivity implements OnRet
isRefreshed = false;
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeContainer);
new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.ONESTATUS, statusId,null, false, ShowConversationActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.ONESTATUS, statusId,null, false,false, ShowConversationActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
if( theme == Helper.THEME_LIGHT) {
swipeRefreshLayout.setColorSchemeResources(R.color.colorAccent,
@ -176,7 +176,7 @@ public class ShowConversationActivity extends AppCompatActivity implements OnRet
@Override
public void onRefresh() {
isRefreshed = true;
new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.ONESTATUS, statusId,null, false, ShowConversationActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.ONESTATUS, statusId,null, false,false, ShowConversationActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
lv_status = (ListView) findViewById(R.id.lv_status);
@ -193,7 +193,7 @@ public class ShowConversationActivity extends AppCompatActivity implements OnRet
@Override
public void run() {
isRefreshed = true;
new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.ONESTATUS, statusId,null, false, ShowConversationActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new RetrieveFeedsAsyncTask(getApplicationContext(), RetrieveFeedsAsyncTask.Type.ONESTATUS, statusId,null, false, false, ShowConversationActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}, 1000);

View File

@ -39,6 +39,7 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
private String targetedID;
private String tag;
private boolean showMediaOnly = false;
private boolean showPinned = false;
private boolean refreshData;
public enum Type{
@ -61,7 +62,7 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
this.refreshData = true;
}
public RetrieveFeedsAsyncTask(Context context, Type action, String targetedID, String max_id, boolean showMediaOnly, OnRetrieveFeedsInterface onRetrieveFeedsInterface){
public RetrieveFeedsAsyncTask(Context context, Type action, String targetedID, String max_id, boolean showMediaOnly, boolean showPinned, OnRetrieveFeedsInterface onRetrieveFeedsInterface){
this.context = context;
this.action = action;
this.max_id = max_id;
@ -69,6 +70,7 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
this.targetedID = targetedID;
this.showMediaOnly = showMediaOnly;
this.refreshData = true;
this.showPinned = showPinned;
}
public RetrieveFeedsAsyncTask(Context context, Type action, String tag, String targetedID, String max_id, OnRetrieveFeedsInterface onRetrieveFeedsInterface){
this.context = context;
@ -98,10 +100,12 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
apiResponse = api.getFavourites(max_id);
break;
case USER:
if( !showMediaOnly)
apiResponse = api.getStatus(targetedID, max_id);
else
if( showMediaOnly)
apiResponse = api.getStatusWithMedia(targetedID, max_id);
else if (showPinned)
apiResponse = api.getPinnedStatuses(targetedID, max_id);
else
apiResponse = api.getStatus(targetedID, max_id);
break;
case ONESTATUS:
apiResponse = api.getStatusbyId(targetedID);

View File

@ -93,7 +93,9 @@ public class API {
AUTHORIZE,
REJECT,
REPORT,
REMOTE_FOLLOW
REMOTE_FOLLOW,
PIN,
UNPIN
}
public API(Context context) {
@ -274,7 +276,7 @@ public class API {
* @return APIResponse
*/
public APIResponse getStatus(String accountId) {
return getStatus(accountId, false, false, null, null, tootPerPage);
return getStatus(accountId, false, false, false, null, null, tootPerPage);
}
/**
@ -285,7 +287,7 @@ public class API {
* @return APIResponse
*/
public APIResponse getStatus(String accountId, String max_id) {
return getStatus(accountId, false, false, max_id, null, tootPerPage);
return getStatus(accountId, false, false, false, max_id, null, tootPerPage);
}
/**
@ -296,9 +298,19 @@ public class API {
* @return APIResponse
*/
public APIResponse getStatusWithMedia(String accountId, String max_id) {
return getStatus(accountId, true, false, max_id, null, tootPerPage);
return getStatus(accountId, true, false, false, max_id, null, tootPerPage);
}
/**
* Retrieves pinned status(es) *synchronously*
*
* @param accountId String Id of the account
* @param max_id String id max
* @return APIResponse
*/
public APIResponse getPinnedStatuses(String accountId, String max_id) {
return getStatus(accountId, false, true, false, max_id, null, tootPerPage);
}
/**
* Retrieves status for the account *synchronously*
@ -311,7 +323,7 @@ public class API {
* @param limit int limit - max value 40
* @return APIResponse
*/
private APIResponse getStatus(String accountId, boolean onlyMedia,
private APIResponse getStatus(String accountId, boolean onlyMedia, boolean pinned,
boolean exclude_replies, String max_id, String since_id, int limit) {
RequestParams params = new RequestParams();
@ -325,6 +337,8 @@ public class API {
limit = 40;
if( onlyMedia)
params.put("only_media", Boolean.toString(true));
if( pinned)
params.put("pinned", Boolean.toString(true));
params.put("limit", String.valueOf(limit));
statuses = new ArrayList<>();
get(String.format("/accounts/%s/statuses", accountId), params, new JsonHttpResponseHandler() {
@ -835,6 +849,12 @@ public class API {
case UNMUTE:
action = String.format("/accounts/%s/unmute", targetedId);
break;
case PIN:
action = String.format("/statuses/%s/pin", targetedId);
break;
case UNPIN:
action = String.format("/statuses/%s/unpin", targetedId);
break;
case UNSTATUS:
action = String.format("/statuses/%s", targetedId);
break;

View File

@ -42,6 +42,7 @@ public class Status implements Parcelable {
private int favourites_count;
private boolean reblogged;
private boolean favourited;
private boolean pinned;
private boolean sensitive;
private String spoiler_text;
private String visibility;
@ -51,6 +52,7 @@ public class Status implements Parcelable {
private List<Status> replies;
private List<Mention> mentions;
private List<Tag> tags;
private List<Status> pins;
private Application application;
private String language;
private boolean isTranslated = false;
@ -81,6 +83,9 @@ public class Status implements Parcelable {
isTranslated = in.readByte() != 0;
isTranslationShown = in.readByte() != 0;
isNew = in.readByte() != 0;
pinned = false;
pins = null;
}
public Status(){}
@ -201,6 +206,14 @@ public class Status implements Parcelable {
this.favourited = favourited;
}
public void setPinned(boolean pinned) { this.pinned = pinned; }
public boolean isPinned() { return pinned; }
public List<Status> getPins() { return pins; }
public void setPins(List<Status> pins) { this.pins = pins; }
public boolean isSensitive() {
return sensitive;
}

View File

@ -0,0 +1,48 @@
package fr.gouv.etalab.mastodon.client.Entities;
import android.support.annotation.NonNull;
/**
* Created by Thomas on 15/09/2017.
*/
public class Version implements Comparable<Version> {
private String version;
public final String get() {
return this.version;
}
public Version(String version) {
if(version == null)
throw new IllegalArgumentException("Version can not be null");
version = version.replaceAll("[^\\d.]", "");
if(!version.matches("[0-9]+(\\.[0-9]+)*"))
throw new IllegalArgumentException("Invalid version format");
this.version = version;
}
@Override public int compareTo(@NonNull Version that) {
String[] thisParts = this.get().split("\\.");
String[] thatParts = that.get().split("\\.");
int length = Math.max(thisParts.length, thatParts.length);
for(int i = 0; i < length; i++) {
int thisPart = i < thisParts.length ?
Integer.parseInt(thisParts[i]) : 0;
int thatPart = i < thatParts.length ?
Integer.parseInt(thatParts[i]) : 0;
if(thisPart < thatPart)
return -1;
if(thisPart > thatPart)
return 1;
}
return 0;
}
@Override public boolean equals(Object that) {
return this == that || that != null && this.getClass() == that.getClass() && this.compareTo((Version) that) == 0;
}
}

View File

@ -14,7 +14,6 @@ package fr.gouv.etalab.mastodon.drawers;
* 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.graphics.Paint;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.content.ClipData;
@ -71,20 +70,22 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import fr.gouv.etalab.mastodon.activities.MediaActivity;
import fr.gouv.etalab.mastodon.activities.ShowAccountActivity;
import fr.gouv.etalab.mastodon.activities.ShowConversationActivity;
import fr.gouv.etalab.mastodon.activities.TootActivity;
import fr.gouv.etalab.mastodon.asynctasks.PostActionAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask;;
import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.APIResponse;
import fr.gouv.etalab.mastodon.client.Entities.Attachment;
import fr.gouv.etalab.mastodon.client.Entities.Error;
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.OnPostActionInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveInstanceInterface;
import fr.gouv.etalab.mastodon.interfaces.OnTranslatedInterface;
import fr.gouv.etalab.mastodon.translation.GoogleTranslateQuery;
import fr.gouv.etalab.mastodon.translation.YandexQuery;
@ -92,31 +93,35 @@ import mastodon.etalab.gouv.fr.mastodon.R;
import static fr.gouv.etalab.mastodon.activities.MainActivity.currentLocale;
import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor;
import static fr.gouv.etalab.mastodon.helper.Helper.shortnameToUnicode;
/**
* Created by Thomas on 24/04/2017.
* Adapter for Status
*/
public class StatusListAdapter extends BaseAdapter implements OnPostActionInterface, OnTranslatedInterface {
public class StatusListAdapter extends BaseAdapter implements OnPostActionInterface, OnTranslatedInterface, OnRetrieveFeedsInterface {
private Context context;
private List<Status> statuses;
private LayoutInflater layoutInflater;
private ImageLoader imageLoader;
private DisplayImageOptions options;
private ViewHolder holder;
private boolean isOnWifi;
private int translator;
private int behaviorWithAttachments;
private StatusListAdapter statusListAdapter;
private final int REBLOG = 1;
private final int FAVOURITE = 2;
private final int PIN = 3;
private final int UNPIN = 4;
private RetrieveFeedsAsyncTask.Type type;
private String targetedId;
private HashMap<String, String> urlConversion;
private HashMap<String, String> tagConversion;
private List<Status> pins;
public StatusListAdapter(Context context, RetrieveFeedsAsyncTask.Type type, String targetedId, boolean isOnWifi, int behaviorWithAttachments, int translator, List<Status> statuses){
this.context = context;
this.statuses = statuses;
@ -127,6 +132,10 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
this.type = type;
this.targetedId = targetedId;
this.translator = translator;
pins = new ArrayList<>();
}
@ -166,7 +175,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
.cacheOnDisk(true).resetViewBeforeLoading(true).build();
final Status status = statuses.get(position);
final ViewHolder holder;
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.drawer_status, parent, false);
holder = new ViewHolder();
@ -182,6 +191,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
holder.status_account_profile_boost_by = (ImageView) convertView.findViewById(R.id.status_account_profile_boost_by);
holder.status_favorite_count = (TextView) convertView.findViewById(R.id.status_favorite_count);
holder.status_reblog_count = (TextView) convertView.findViewById(R.id.status_reblog_count);
holder.status_pin = (ImageView) convertView.findViewById(R.id.status_pin);
holder.status_toot_date = (TextView) convertView.findViewById(R.id.status_toot_date);
holder.status_show_more = (Button) convertView.findViewById(R.id.status_show_more);
holder.status_more = (ImageView) convertView.findViewById(R.id.status_more);
@ -220,6 +230,8 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
//Display a preview for accounts that have replied *if enabled and only for home timeline*
if( type == RetrieveFeedsAsyncTask.Type.HOME ) {
boolean showPreview = sharedpreferences.getBoolean(Helper.SET_PREVIEW_REPLIES, false);
@ -431,10 +443,6 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
holder.status_content_translated_container.setVisibility(View.GONE);
}
//Hides action bottom bar action when looking to status trough accounts
if( type == RetrieveFeedsAsyncTask.Type.USER){
holder.status_action_container.setVisibility(View.GONE);
}
//Manages theme for icon colors
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
if( theme == Helper.THEME_DARK){
@ -446,6 +454,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
changeDrawableColor(context, R.drawable.ic_local_post_office,R.color.dark_text);
changeDrawableColor(context, R.drawable.ic_retweet_black,R.color.dark_text);
changeDrawableColor(context, R.drawable.ic_fav_black,R.color.dark_text);
changeDrawableColor(context, R.drawable.ic_action_pin, R.color.dark_text);
changeDrawableColor(context, R.drawable.ic_photo,R.color.dark_text);
changeDrawableColor(context, R.drawable.ic_remove_red_eye,R.color.dark_text);
changeDrawableColor(context, R.drawable.ic_translate,R.color.dark_text);
@ -458,6 +467,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
changeDrawableColor(context, R.drawable.ic_local_post_office,R.color.black);
changeDrawableColor(context, R.drawable.ic_retweet_black,R.color.black);
changeDrawableColor(context, R.drawable.ic_fav_black,R.color.black);
changeDrawableColor(context, R.drawable.ic_action_pin, R.color.black);
changeDrawableColor(context, R.drawable.ic_photo,R.color.white);
changeDrawableColor(context, R.drawable.ic_remove_red_eye,R.color.white);
changeDrawableColor(context, R.drawable.ic_translate,R.color.white);
@ -713,6 +723,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
imgFav.setBounds(0,0,(int) (20 * iconSizePercent/100 * scale + 0.5f),(int) (20 * iconSizePercent/100 * scale + 0.5f));
imgReblog.setBounds(0,0,(int) (20 * iconSizePercent/100 * scale + 0.5f),(int) (20 * iconSizePercent/100 * scale + 0.5f));
holder.status_favorite_count.setCompoundDrawables(imgFav, null, null, null);
holder.status_reblog_count.setCompoundDrawables(imgReblog, null, null, null);
@ -720,6 +731,42 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
holder.status_show_more.setTextColor(ContextCompat.getColor(context, R.color.white));
holder.status_spoiler_button.setTextColor(ContextCompat.getColor(context, R.color.white));
}
boolean isOwner = status.getAccount().getId().equals(userId);
// Pinning toots is only available on Mastodon 1._6_.0 instances.
if (isOwner && Helper.canPin && (status.getVisibility().equals("public") || status.getVisibility().equals("unlisted"))) {
final Drawable imgUnPinToot, imgPinToot;
imgUnPinToot = ContextCompat.getDrawable(context, R.drawable.ic_action_pin);
imgPinToot = ContextCompat.getDrawable(context, R.drawable.ic_action_pin_yellow);
imgUnPinToot.setBounds(0,0,(int) (20 * iconSizePercent/100 * scale + 0.5f),(int) (20 * iconSizePercent/100 * scale + 0.5f));
imgPinToot.setBounds(0,0,(int) (20 * iconSizePercent/100 * scale + 0.5f),(int) (20 * iconSizePercent/100 * scale + 0.5f));
if (status.isPinned())
holder.status_pin.setImageDrawable(imgPinToot);
else
holder.status_pin.setImageDrawable(imgUnPinToot);
holder.status_pin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/* Code is in for displayConfirmationDialog() but we don't call it.
* Need to make sure we can successfully get a pinned toots list by
* this point, after async call earlier.
*/
pinAction(status);
}
});
holder.status_pin.setVisibility(View.VISIBLE);
}
else {
holder.status_pin.setVisibility(View.GONE);
}
holder.status_show_more.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -777,6 +824,8 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
reblogAction(status);
}
});
switch (status.getVisibility()){
case "direct":
case "private":
@ -858,7 +907,22 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
statusListAdapter.notifyDataSetChanged();
}
/**
* Pin or unpin a status
* @param status Status
*/
private void pinAction(Status status) {
if (status.isPinned()) {
new PostActionAsyncTask(context, API.StatusAction.UNPIN, status.getId(), StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
holder.status_pin.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_pin));
} else {
new PostActionAsyncTask(context, API.StatusAction.PIN, status.getId(), StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
holder.status_pin.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_pin_yellow));
}
statusListAdapter.notifyDataSetChanged();
}
private void loadAttachments(final Status status, ViewHolder holder){
List<Attachment> attachments = status.getMedia_attachments();
@ -943,11 +1007,39 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
holder.status_show_more.setVisibility(View.GONE);
}
@Override
public void onRetrieveFeeds(APIResponse apiResponse, boolean refreshData) {
if( apiResponse.getError() != null){
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true);
if( show_error_messages)
Toast.makeText(context, apiResponse.getError().getError(),Toast.LENGTH_LONG).show();
return;
}
pins = apiResponse.getStatuses();
for (Status haystack : statuses)
{
for (Status pin : pins) {
if (haystack.getId().equals(pin.getId()))
{
haystack.setPinned(true);
break;
}
}
}
}
@Override
public void onPostAction(int statusCode, API.StatusAction statusAction, String targetedId, Error error) {
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
if( error != null){
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true);
if( show_error_messages)
Toast.makeText(context, error.getError(),Toast.LENGTH_LONG).show();
@ -971,6 +1063,25 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
statuses.removeAll(statusesToRemove);
statusListAdapter.notifyDataSetChanged();
}
else if ( statusAction == API.StatusAction.PIN || statusAction == API.StatusAction.UNPIN ) {
Status toCheck = null;
for (Status checkPin: statuses) {
if (checkPin.getId().equals(targetedId)) {
toCheck = checkPin;
break;
}
}
if (statusAction == API.StatusAction.PIN) {
if (toCheck != null)
toCheck.setPinned(true);
}
else {
if (toCheck != null)
toCheck.setPinned(false);
}
statusListAdapter.notifyDataSetChanged();
}
}
@Override
@ -1096,6 +1207,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
ImageView status_prev4_play;
RelativeLayout status_prev4_container;
ImageView status_reply;
ImageView status_pin;
ImageView status_privacy;
FloatingActionButton status_translate;
LinearLayout status_container2;
@ -1131,7 +1243,12 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
title = context.getString(R.string.reblog_remove);
else
title = context.getString(R.string.reblog_add);
}else if ( action == PIN) {
title = context.getString(R.string.pin_add);
}else if (action == UNPIN) {
title = context.getString(R.string.pin_remove);
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
@ -1148,6 +1265,10 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
reblogAction(status);
else if( action == FAVOURITE)
favouriteAction(status);
else if ( action == PIN)
pinAction(status);
else if ( action == UNPIN)
pinAction(status);
dialog.dismiss();
}
})

View File

@ -71,7 +71,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
private ListView lv_status;
private boolean isOnWifi;
private int behaviorWithAttachments;
private boolean showMediaOnly;
private boolean showMediaOnly, showPinned;
private int positionSpinnerTrans;
private boolean hideHeader;
private String instanceValue;
@ -90,6 +90,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
boolean comesFromSearch = false;
hideHeader = false;
showMediaOnly = false;
showPinned = false;
if (bundle != null) {
type = (RetrieveFeedsAsyncTask.Type) bundle.get("type");
targetedId = bundle.getString("targetedId", null);
@ -97,6 +98,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
instanceValue = bundle.getString("hideHeaderValue", null);
hideHeader = bundle.getBoolean("hideHeader", false);
showMediaOnly = bundle.getBoolean("showMediaOnly",false);
showPinned = bundle.getBoolean("showPinned",false);
if( bundle.containsKey("statuses")){
ArrayList<Parcelable> statusesReceived = bundle.getParcelableArrayList("statuses");
assert statusesReceived != null;
@ -162,7 +164,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
if(!flag_loading ) {
flag_loading = true;
if( type == RetrieveFeedsAsyncTask.Type.USER)
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else if( type == RetrieveFeedsAsyncTask.Type.TAG)
asyncTask = new RetrieveFeedsAsyncTask(context, type, tag, targetedId, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
@ -187,7 +189,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
swiped = true;
MainActivity.countNewStatus = 0;
if( type == RetrieveFeedsAsyncTask.Type.USER)
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else if( type == RetrieveFeedsAsyncTask.Type.TAG)
asyncTask = new RetrieveFeedsAsyncTask(context, type, tag, targetedId, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
@ -199,7 +201,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
R.color.mastodonC3);
if( type == RetrieveFeedsAsyncTask.Type.USER)
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
asyncTask = new RetrieveFeedsAsyncTask(context, type, targetedId, max_id, showMediaOnly, showPinned, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else if( type == RetrieveFeedsAsyncTask.Type.TAG)
asyncTask = new RetrieveFeedsAsyncTask(context, type, tag, targetedId, max_id, DisplayStatusFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else

View File

@ -268,6 +268,7 @@ public class Helper {
private static boolean menuAccountsOpened = false;
public static boolean canPin;
private static final Pattern SHORTNAME_PATTERN = Pattern.compile(":( |)([-+\\w]+):");
@ -525,11 +526,15 @@ public class Helper {
message = context.getString(R.string.toast_favourite);
}else if(statusAction == API.StatusAction.UNFAVOURITE){
message = context.getString(R.string.toast_unfavourite);
}else if(statusAction == API.StatusAction.PIN){
message = context.getString(R.string.toast_pin);
}else if (statusAction == API.StatusAction.UNPIN){
message = context.getString(R.string.toast_unpin);
}else if(statusAction == API.StatusAction.REPORT){
message = context.getString(R.string.toast_report);
}else if(statusAction == API.StatusAction.UNSTATUS){
message = context.getString(R.string.toast_unstatus);
}
}
}else {
message = context.getString(R.string.toast_error);
}
@ -1571,7 +1576,7 @@ public class Helper {
navigationView.getMenu().findItem(R.id.nav_local).setVisible(false);
navigationView.getMenu().findItem(R.id.nav_global).setVisible(false);
navigationView.getMenu().findItem(R.id.nav_notification).setVisible(false);
params.height = (int) Helper.convertDpToPixel(heightSearchdp, activity);;
params.height = (int) Helper.convertDpToPixel(heightSearchdp, activity);
toolbar_search_container.setLayoutParams(params);
tableLayout.setVisibility(View.VISIBLE);
break;
@ -1589,7 +1594,7 @@ public class Helper {
navigationView.getMenu().findItem(R.id.nav_local).setVisible(true);
navigationView.getMenu().findItem(R.id.nav_global).setVisible(true);
navigationView.getMenu().findItem(R.id.nav_notification).setVisible(true);
params.height = (int) Helper.convertDpToPixel(heightSearchdp, activity);;
params.height = (int) Helper.convertDpToPixel(heightSearchdp, activity);
toolbar_search_container.setLayoutParams(params);
tableLayout.setVisibility(View.VISIBLE);
break;

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

View File

@ -377,6 +377,14 @@
android:layout_height="20dp"
android:src="@drawable/ic_reply"
tools:ignore="ContentDescription" />
<ImageView
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:id="@+id/status_pin"
android:layout_gravity="center_vertical"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/ic_action_pin"/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"

View File

@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_show_pinned"
android:title="@string/pinned_toots"
android:icon="@drawable/ic_action_pin"
app:showAsAction="always" />
<item
android:id="@+id/action_show_media"
android:title="@string/media"

View File

@ -97,6 +97,8 @@
<string name="favourite_remove">Remove this toot from your favourites?</string>
<string name="reblog_add">Boost this toot?</string>
<string name="reblog_remove">Unboost this toot?</string>
<string name="pin_add">Pin this toot?</string>
<string name="pin_remove">Unpin this toot?</string>
<string-array name="more_action">
<item>Mute</item>
<item>Block</item>
@ -212,6 +214,7 @@
<string name="status_cnt">Toots \n %d</string>
<string name="following_cnt">Following \n %d</string>
<string name="followers_cnt">Followers \n %d</string>
<string name="pins_cnt">Pinned \n %d</string>
<string name="authorize">Authorize</string>
<string name="reject">Reject</string>
@ -246,6 +249,7 @@
<!-- HEADER -->
<string name="following">Following</string>
<string name="followers">Followers</string>
<string name="pinned_toots">Pinned</string>
<!-- TOAST -->
<string name="client_error">Unable to get client id!</string>
<string name="no_internet">No Internet connection!</string>
@ -261,6 +265,8 @@
<string name="toast_unfavourite">The toot was removed from your favourites!</string>
<string name="toast_report">The toot was reported!</string>
<string name="toast_unstatus">The toot was deleted!</string>
<string name="toast_pin">The toot was pinned!</string>
<string name="toast_unpin">The toot was unpinned!</string>
<string name="toast_error">Oops ! An error occurred!</string>
<string name="toast_code_error">An error occurred! The instance did not return an authorisation code!</string>
<string name="toast_error_instance">The instance domain does not seem to be valide!</string>

View File

@ -76,17 +76,21 @@ import java.util.Locale;
import java.util.Stack;
import java.util.regex.Matcher;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveInstanceAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveMetaDataAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.UpdateAccountInfoByIDAsyncTask;
import fr.gouv.etalab.mastodon.client.APIResponse;
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.Entities.Version;
import fr.gouv.etalab.mastodon.client.PatchBaseImageDownloader;
import fr.gouv.etalab.mastodon.fragments.DisplayAccountsFragment;
import fr.gouv.etalab.mastodon.fragments.DisplayFollowRequestSentFragment;
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.OnRetrieveInstanceInterface;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMetaDataInterface;
import fr.gouv.etalab.mastodon.interfaces.OnUpdateAccountInfoInterface;
import fr.gouv.etalab.mastodon.services.StreamingService;
@ -114,7 +118,7 @@ import android.support.v4.app.FragmentStatePagerAdapter;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, OnUpdateAccountInfoInterface, ProviderInstaller.ProviderInstallListener, OnRetrieveMetaDataInterface {
implements NavigationView.OnNavigationItemSelectedListener, OnUpdateAccountInfoInterface, ProviderInstaller.ProviderInstallListener, OnRetrieveMetaDataInterface, OnRetrieveInstanceInterface {
private FloatingActionButton toot;
private HashMap<String, String> tagTile = new HashMap<>();
@ -215,6 +219,7 @@ public class MainActivity extends AppCompatActivity
startService(intent);
}
}
Helper.canPin = false;
Helper.fillMapEmoji(getApplicationContext());
//Here, the user is authenticated
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
@ -569,7 +574,8 @@ public class MainActivity extends AppCompatActivity
}
Helper.switchLayout(MainActivity.this);
// Retrieves instance
new RetrieveInstanceAsyncTask(getApplicationContext(), MainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@ -1146,6 +1152,18 @@ public class MainActivity extends AppCompatActivity
}
}
@Override
public void onRetrieveInstance(APIResponse apiResponse) {
if( apiResponse.getError() != null){
return;
}
if( apiResponse.getInstance() == null || apiResponse.getInstance().getVersion() == null || apiResponse.getInstance().getVersion().trim().length() == 0)
return;
Version currentVersion = new Version(apiResponse.getInstance().getVersion());
Version minVersion = new Version("1.6");
Helper.canPin = (currentVersion.compareTo(minVersion) == 1 || currentVersion.equals(minVersion));
}
/**
* Page Adapter for settings