Merge branch 'nitter_follow_accounts' into develop

This commit is contained in:
tom79 2019-12-08 18:26:57 +01:00
commit 14f9d7f4ee
12 changed files with 458 additions and 101 deletions

View File

@ -160,13 +160,19 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
AutoCompleteTextView instance_list = dialogView.findViewById(R.id.search_instance);
//Manage download of attachments
RadioGroup radioGroup = dialogView.findViewById(R.id.set_attachment_group);
radioGroup.setOnCheckedChangeListener((group, checkedId) -> {
if( checkedId == R.id.twitter_accounts){
instance_list.setHint(R.string.list_of_twitter_accounts);
}else {
instance_list.setHint(R.string.instance);
}
});
instance_list.setFilters(new InputFilter[]{new InputFilter.LengthFilter(60)});
dialogBuilder.setPositiveButton(R.string.validate, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
String instanceName = instance_list.getText().toString().trim();
String instanceName = instance_list.getText().toString().trim().replace("@","");
new Thread(new Runnable() {
@Override
public void run() {
@ -182,7 +188,6 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
} else if (radioGroup.getCheckedRadioButtonId() == R.id.gnu_instance) {
new HttpsConnection(ReorderTimelinesActivity.this, null).get("https://" + instanceName + "/api/statuses/public_timeline.json", 10, null, null);
}
runOnUiThread(new Runnable() {
public void run() {
dialog.dismiss();
@ -196,6 +201,8 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
new InstancesDAO(ReorderTimelinesActivity.this, db).insertInstance(instanceName, "MISSKEY");
} else if (radioGroup.getCheckedRadioButtonId() == R.id.gnu_instance) {
new InstancesDAO(ReorderTimelinesActivity.this, db).insertInstance(instanceName, "GNU");
}else if (radioGroup.getCheckedRadioButtonId() == R.id.twitter_accounts) {
new InstancesDAO(ReorderTimelinesActivity.this, db).insertInstance(instanceName, "NITTER");
}
if (timelines != null && adapter != null) {
List<RemoteInstance> instance = new InstancesDAO(ReorderTimelinesActivity.this, db).getInstanceByName(instanceName);
@ -256,78 +263,84 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
@Override
public void afterTextChanged(Editable s) {
Pattern host = Pattern.compile("([\\da-z\\.-]+\\.[a-z\\.]{2,12})");
Matcher matcher = host.matcher(s.toString().trim());
if (s.toString().trim().length() == 0 || !matcher.find()) {
alertDialog.getButton(
AlertDialog.BUTTON_POSITIVE).setEnabled(false);
} else {
// Something into edit text. Enable the button.
if (radioGroup.getCheckedRadioButtonId() != R.id.twitter_accounts){
Pattern host = Pattern.compile("([\\da-z\\.-]+\\.[a-z\\.]{2,12})");
Matcher matcher = host.matcher(s.toString().trim());
if (s.toString().trim().length() == 0 || !matcher.find()) {
alertDialog.getButton(
AlertDialog.BUTTON_POSITIVE).setEnabled(false);
} else {
// Something into edit text. Enable the button.
alertDialog.getButton(
AlertDialog.BUTTON_POSITIVE).setEnabled(true);
}
if (s.length() > 2 && !isLoadingInstance) {
final String action = "/instances/search";
final HashMap<String, String> parameters = new HashMap<>();
parameters.put("q", s.toString().trim());
parameters.put("count", String.valueOf(1000));
parameters.put("name", String.valueOf(true));
isLoadingInstance = true;
if (oldSearch == null || !oldSearch.equals(s.toString().trim()))
new Thread(new Runnable() {
@Override
public void run() {
try {
final String response = new HttpsConnection(ReorderTimelinesActivity.this, null).get("https://instances.social/api/1.0" + action, 30, parameters, Helper.THEKINRAR_SECRET_TOKEN);
runOnUiThread(new Runnable() {
public void run() {
isLoadingInstance = false;
String[] instances;
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray jsonArray = jsonObject.getJSONArray("instances");
if (jsonArray != null) {
int length = 0;
for (int i = 0; i < jsonArray.length(); i++) {
if (!jsonArray.getJSONObject(i).get("name").toString().contains("@") && jsonArray.getJSONObject(i).get("up").toString().equals("true"))
length++;
}
instances = new String[length];
int j = 0;
for (int i = 0; i < jsonArray.length(); i++) {
if (!jsonArray.getJSONObject(i).get("name").toString().contains("@") && jsonArray.getJSONObject(i).get("up").toString().equals("true")) {
instances[j] = jsonArray.getJSONObject(i).get("name").toString();
j++;
}
}
} else {
instances = new String[]{};
}
instance_list.setAdapter(null);
ArrayAdapter<String> adapter =
new ArrayAdapter<>(ReorderTimelinesActivity.this, android.R.layout.simple_list_item_1, instances);
instance_list.setAdapter(adapter);
if (instance_list.hasFocus() && !ReorderTimelinesActivity.this.isFinishing())
instance_list.showDropDown();
oldSearch = s.toString().trim();
} catch (JSONException ignored) {
isLoadingInstance = false;
}
}
});
} catch (HttpsConnection.HttpsConnectionException e) {
isLoadingInstance = false;
} catch (Exception e) {
isLoadingInstance = false;
}
}
}).start();
else
isLoadingInstance = false;
}
}else {
alertDialog.getButton(
AlertDialog.BUTTON_POSITIVE).setEnabled(true);
}
if (s.length() > 2 && !isLoadingInstance) {
final String action = "/instances/search";
final HashMap<String, String> parameters = new HashMap<>();
parameters.put("q", s.toString().trim());
parameters.put("count", String.valueOf(1000));
parameters.put("name", String.valueOf(true));
isLoadingInstance = true;
if (oldSearch == null || !oldSearch.equals(s.toString().trim()))
new Thread(new Runnable() {
@Override
public void run() {
try {
final String response = new HttpsConnection(ReorderTimelinesActivity.this, null).get("https://instances.social/api/1.0" + action, 30, parameters, Helper.THEKINRAR_SECRET_TOKEN);
runOnUiThread(new Runnable() {
public void run() {
isLoadingInstance = false;
String[] instances;
try {
JSONObject jsonObject = new JSONObject(response);
JSONArray jsonArray = jsonObject.getJSONArray("instances");
if (jsonArray != null) {
int length = 0;
for (int i = 0; i < jsonArray.length(); i++) {
if (!jsonArray.getJSONObject(i).get("name").toString().contains("@") && jsonArray.getJSONObject(i).get("up").toString().equals("true"))
length++;
}
instances = new String[length];
int j = 0;
for (int i = 0; i < jsonArray.length(); i++) {
if (!jsonArray.getJSONObject(i).get("name").toString().contains("@") && jsonArray.getJSONObject(i).get("up").toString().equals("true")) {
instances[j] = jsonArray.getJSONObject(i).get("name").toString();
j++;
}
}
} else {
instances = new String[]{};
}
instance_list.setAdapter(null);
ArrayAdapter<String> adapter =
new ArrayAdapter<>(ReorderTimelinesActivity.this, android.R.layout.simple_list_item_1, instances);
instance_list.setAdapter(adapter);
if (instance_list.hasFocus() && !ReorderTimelinesActivity.this.isFinishing())
instance_list.showDropDown();
oldSearch = s.toString().trim();
} catch (JSONException ignored) {
isLoadingInstance = false;
}
}
});
} catch (HttpsConnection.HttpsConnectionException e) {
isLoadingInstance = false;
} catch (Exception e) {
isLoadingInstance = false;
}
}
}).start();
else
isLoadingInstance = false;
}
}
});
}

View File

@ -249,7 +249,15 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
status.setType(action);
}
}
} else if (remoteInstanceObj != null && remoteInstanceObj.size() > 0 && remoteInstanceObj.get(0).getType().equals("PIXELFED")) {
} else if (remoteInstanceObj != null && remoteInstanceObj.size() > 0 && remoteInstanceObj.get(0).getType().equals("NITTER")) {
apiResponse = api.getNitter(this.instanceName, max_id);
List<app.fedilab.android.client.Entities.Status> statusesTemp = apiResponse.getStatuses();
if (statusesTemp != null) {
for (app.fedilab.android.client.Entities.Status status : statusesTemp) {
status.setType(action);
}
}
}else if (remoteInstanceObj != null && remoteInstanceObj.size() > 0 && remoteInstanceObj.get(0).getType().equals("PIXELFED")) {
apiResponse = api.getPixelfedTimeline(instanceName, max_id);
} else if (remoteInstanceObj != null && remoteInstanceObj.size() > 0 && remoteInstanceObj.get(0).getType().equals("GNU")) {
apiResponse = api.getGNUTimeline(instanceName, max_id);

View File

@ -20,6 +20,7 @@ import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.gson.JsonArray;
@ -28,15 +29,21 @@ import com.google.gson.JsonObject;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@ -45,6 +52,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
@ -760,6 +769,159 @@ public class API {
return status;
}
/**
* Parse xml response for Nitter
*
* @param xml String
* @return List<Status>
*/
private List<Status> parseNitter(String xml) {
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String nitterHost = sharedpreferences.getString(Helper.SET_NITTER_HOST, Helper.DEFAULT_NITTER_HOST).toLowerCase();
List<Status> statuses = new ArrayList<>();
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput( new StringReader( xml ) );
int eventType = xpp.getEventType();
Account account = null;
Status status = null;
HashMap<String, String> mappedProfile = new HashMap<>();
while (eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_TAG) {
if( xpp.getName().compareTo("item") == 0 ){
status = new Status();
status.setReplies_count(0);
status.setFavourites_count(0);
status.setReblogs_count(0);
status.setFavourited(false);
status.setReblogged(false);
status.setEmojiFound(true);
status.setPollEmojiFound(true);
status.setEmojiTranslateFound(true);
status.setMedia_attachments(new ArrayList<>());
account = new Account();
}else if( xpp.getName().compareTo("creator") == 0 ){
eventType = xpp.next();
if(eventType == XmlPullParser.TEXT) {
if( account != null ){
account.setAcct(xpp.getText().replace("@","")+"@" + nitterHost);
account.setDisplay_name(xpp.getText().replace("@",""));
account.setUsername(xpp.getText().replace("@",""));
account.setId("https://" + nitterHost + "/" + xpp.getText());
account.setUuid("https://" + nitterHost + "/" + xpp.getText());
account.setUrl("https://" + nitterHost + "/" + xpp.getText());
if( !mappedProfile.containsKey(xpp.getText()) ){
HttpsConnection httpsConnection = new HttpsConnection(context, nitterHost);
try {
String response = httpsConnection.get("https://" + nitterHost + "/" + xpp.getText() + "/rss", 10, null, null);
XmlPullParserFactory factory2 = XmlPullParserFactory.newInstance();
factory2.setNamespaceAware(true);
XmlPullParser xpp2 = factory2.newPullParser();
xpp2.setInput( new StringReader( response ) );
int eventType2 = xpp2.getEventType();
while (eventType2 != XmlPullParser.END_DOCUMENT) {
if (eventType2 == XmlPullParser.START_TAG) {
if (xpp2.getName().compareTo("url") == 0) {
eventType2 = xpp2.next();
if(eventType2 == XmlPullParser.TEXT ) {
mappedProfile.put(xpp.getText(), xpp2.getText());
}
break;
}
}
eventType2 = xpp2.next();
}
} catch (NoSuchAlgorithmException | KeyManagementException | HttpsConnection.HttpsConnectionException e) {
e.printStackTrace();
}
}
account.setAvatar(mappedProfile.get(xpp.getText()));
}
}
} else if( xpp.getName().compareTo("pubDate") == 0 ){
eventType = xpp.next();
if(eventType == XmlPullParser.TEXT && status != null) {
if( xpp.getText() != null ) {
try {
DateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
Date date = formatter.parse(xpp.getText());
status.setCreated_at(date);
} catch (ParseException e) {
status.setCreated_at(new Date());
}
}
}
}else if( xpp.getName().compareTo("description") == 0 ){
eventType = xpp.next();
if(eventType == XmlPullParser.TEXT && status != null) {
if( xpp.getText() != null ) {
String description = xpp.getText();
Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>");
Matcher matcher = imgPattern.matcher(description);
List<String> imgs = new ArrayList<>();
int i = 1;
ArrayList<Attachment> attachments = new ArrayList<>();
while (matcher.find()) {
description = description.replaceAll(Pattern.quote(matcher.group()), "");
imgs.add("[media_" + i + "]|" + matcher.group(1));
Attachment attachment = new Attachment();
attachment.setType("image");
attachment.setDescription("");
attachment.setUrl(matcher.group(1));
attachment.setPreview_url(matcher.group(1));
attachment.setId(matcher.group(1));
attachments.add(attachment);
}
status.setMedia_attachments(attachments);
status.setContent(context, description);
}
}
}else if( xpp.getName().compareTo("guid") == 0 ){
eventType = xpp.next();
if(eventType == XmlPullParser.TEXT && status != null) {
if( xpp.getText() != null ) {
status.setUri(xpp.getText());
Pattern idPattern = Pattern.compile("([0-9])+");
Matcher matcher = idPattern.matcher(xpp.getText());
while (matcher.find()) {
status.setId(matcher.group(0));
}
}
}
}else if( xpp.getName().compareTo("link") == 0 ){
eventType = xpp.next();
if(eventType == XmlPullParser.TEXT && status != null) {
if( xpp.getText() != null ) {
status.setUrl(xpp.getText());
}
}
}
} else if(eventType == XmlPullParser.END_TAG) {
if( xpp.getName().compareTo("item") == 0 ){
if (status != null) {
status.setAccount(account);
statuses.add(status);
}
account = null;
status = null;
}
}
eventType = xpp.next();
}
} catch (XmlPullParserException | IOException e) {
e.printStackTrace();
}
return statuses;
}
/**
* Parse json response for several notes (Misskey)
*
@ -3237,8 +3399,51 @@ public class API {
return apiResponse;
}
/**
* Retrieves Peertube videos from an instance *synchronously*
* Retrieves Nitter timeline from accounts *synchronously*
*
* @return APIResponse
*/
public APIResponse getNitter(String instance, String max_id) {
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String nitterHost = sharedpreferences.getString(Helper.SET_NITTER_HOST, Helper.DEFAULT_NITTER_HOST).toLowerCase();
String[] usernames = instance.split(" ");
if( usernames.length == 0 ){
Error error = new Error();
error.setError(context.getString(R.string.toast_error));
error.setStatusCode(404);
apiResponse.setError(error);
return apiResponse;
}
StringBuilder urlparams = new StringBuilder();
for(String param: usernames){
urlparams.append(param.trim()).append(",");
}
String url = "https://" + nitterHost + "/" + urlparams + "/rss";
if( max_id != null ){
url += "?max_position=" + max_id;
}
try {
statuses = new ArrayList<>();
HttpsConnection httpsConnection = new HttpsConnection(context, this.instance);
String response = httpsConnection.get(url, 30, null, null);
apiResponse.setMax_id(httpsConnection.getMax_id());
statuses = parseNitter(response);
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
} catch (NoSuchAlgorithmException | IOException | KeyManagementException e) {
e.printStackTrace();
}
apiResponse.setStatuses(statuses);
return apiResponse;
}
/**
* Retrieves Misskey timeline from an instance *synchronously*
*
* @return APIResponse
*/

View File

@ -474,18 +474,20 @@ public class Status implements Parcelable {
account.setInstance(instance);
account.setUrl(url);
String accountId = null;
for (Mention mention : mentions) {
String[] accountMentionAcct = mention.getAcct().split("@");
//Different isntance
if (accountMentionAcct.length > 1) {
if (mention.getAcct().equals(account.getAcct() + "@" + account.getInstance())) {
accountId = mention.getId();
break;
}
} else {
if (mention.getAcct().equals(account.getAcct())) {
accountId = mention.getId();
break;
if( mentions != null) {
for (Mention mention : mentions) {
String[] accountMentionAcct = mention.getAcct().split("@");
//Different isntance
if (accountMentionAcct.length > 1) {
if (mention.getAcct().equals(account.getAcct() + "@" + account.getInstance())) {
accountId = mention.getId();
break;
}
} else {
if (mention.getAcct().equals(account.getAcct())) {
accountId = mention.getId();
break;
}
}
}
}

View File

@ -170,13 +170,18 @@ public class HttpsConnection {
}
}
StringBuilder postData = new StringBuilder();
for (Map.Entry<String, Object> param : params.entrySet()) {
if (postData.length() != 0) postData.append('&');
postData.append(param.getKey());
postData.append('=');
postData.append(param.getValue());
URL url;
if( params.size() > 0 ) {
for (Map.Entry<String, Object> param : params.entrySet()) {
if (postData.length() != 0) postData.append('&');
postData.append(param.getKey());
postData.append('=');
postData.append(param.getValue());
}
url = new URL(urlConnection + "?" + postData);
}else{
url = new URL(urlConnection);
}
URL url = new URL(urlConnection + "?" + postData);
if (Build.VERSION.SDK_INT >= 21) {
OkHttpClient.Builder builder = new OkHttpClient.Builder().connectTimeout(timeout, TimeUnit.SECONDS).cache(new Cache(context.getCacheDir(), cacheSize));
@ -331,6 +336,7 @@ public class HttpsConnection {
throw new HttpsConnectionException(code, error);
}
}
} else {
URL url = new URL(urlConnection);
if (proxy != null)
@ -1443,6 +1449,12 @@ public class HttpsConnection {
}
}
}else if (entry.toString().startsWith("Min-Id") || entry.toString().startsWith("min-id")) {
Pattern patternMaxId = Pattern.compile("min-id=\\[([0-9a-zA-Z]{1,}).*\\]");
Matcher matcherMaxId = patternMaxId.matcher(entry.toString());
if (matcherMaxId.find()) {
max_id = matcherMaxId.group(1);
}
}
}
}
@ -1454,6 +1466,7 @@ public class HttpsConnection {
if (httpsURLConnection == null)
return;
Map<String, List<String>> map = httpsURLConnection.getHeaderFields();
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
if (entry.toString().startsWith("Link") || entry.toString().startsWith("link")) {
Pattern patternMaxId = Pattern.compile("max_id=([0-9a-zA-Z]{1,}).*");
@ -1469,6 +1482,12 @@ public class HttpsConnection {
}
}
}else if (entry.toString().startsWith("Min-Id") || entry.toString().startsWith("min-id")) {
Pattern patternMaxId = Pattern.compile("min-id=\\[([0-9a-zA-Z]{1,}).*\\]");
Matcher matcherMaxId = patternMaxId.matcher(entry.toString());
if (matcherMaxId.find()) {
max_id = matcherMaxId.group(1);
}
}
}
} else {

View File

@ -129,6 +129,9 @@ public class ReorderTabAdapter extends RecyclerView.Adapter<ReorderTabAdapter.It
case "GNU":
holder.iconView.setImageResource(R.drawable.ic_gnu_social);
break;
case "NITTER":
holder.iconView.setImageResource(R.drawable.nitter);
break;
}
holder.textView.setText(tl.getRemoteInstance().getHost());
break;

View File

@ -227,6 +227,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
private List<ViewHolder> lstHolders;
private List<Emojis> emojisPicker;
private Status statusForQuickReply;
private String instanceType;
private Runnable updateAnimatedEmoji = new Runnable() {
@Override
@ -266,6 +267,21 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
currentToId = -1;
}
public StatusListAdapter(String instanceType, RetrieveFeedsAsyncTask.Type type, String targetedId, boolean isOnWifi, List<Status> statuses) {
super();
this.statuses = statuses;
this.isOnWifi = isOnWifi;
statusListAdapter = this;
this.type = type;
this.targetedId = targetedId;
redraft = false;
lstHolders = new ArrayList<>();
toot_content = null;
toot_cw_content = null;
tootReply = null;
currentToId = -1;
this.instanceType = instanceType;
}
public StatusListAdapter(TagTimeline tagTimeline, String targetedId, boolean isOnWifi, List<Status> statuses) {
super();
@ -283,6 +299,23 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
currentToId = -1;
}
public StatusListAdapter(String instanceType, TagTimeline tagTimeline, String targetedId, boolean isOnWifi, List<Status> statuses) {
super();
this.statuses = statuses;
this.isOnWifi = isOnWifi;
statusListAdapter = this;
this.type = RetrieveFeedsAsyncTask.Type.TAG;
this.targetedId = targetedId;
redraft = false;
this.tagTimeline = tagTimeline;
this.instanceType = instanceType;
lstHolders = new ArrayList<>();
toot_content = null;
toot_cw_content = null;
tootReply = null;
currentToId = -1;
}
public StatusListAdapter(int position, String targetedId, boolean isOnWifi, List<Status> statuses) {
this.statuses = statuses;
this.isOnWifi = isOnWifi;
@ -616,15 +649,20 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
show_boosts = ((ShowAccountActivity) context).showBoosts();
show_replies = ((ShowAccountActivity) context).showReplies();
}
if (type != RetrieveFeedsAsyncTask.Type.REMOTE_INSTANCE && type != RetrieveFeedsAsyncTask.Type.NEWS && !Helper.filterToots(statuses.get(position), type, context instanceof ShowAccountActivity, show_boosts, show_replies))
if (type != RetrieveFeedsAsyncTask.Type.REMOTE_INSTANCE && type != RetrieveFeedsAsyncTask.Type.NEWS && !Helper.filterToots(statuses.get(position), type, context instanceof ShowAccountActivity, show_boosts, show_replies)) {
return HIDDEN_STATUS;
}
if (statuses.get(position).isFocused() && type == RetrieveFeedsAsyncTask.Type.CONTEXT && statuses.get(position).getViewType() != CONSOLE_STATUS)
return FOCUSED_STATUS;
else {
if (social == UpdateAccountInfoAsyncTask.SOCIAL.PIXELFED && type == RetrieveFeedsAsyncTask.Type.CONTEXT) {
return COMPACT_STATUS;
} else {
return statuses.get(position).getViewType();
if( instanceType == null || instanceType.compareTo("NITTER") != 0 ) {
return statuses.get(position).getViewType();
}else{
return COMPACT_STATUS;
}
}
}
}
@ -653,6 +691,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
final String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null);
context = viewHolder.itemView.getContext();
if (viewHolder.getItemViewType() != HIDDEN_STATUS) {
final ViewHolder holder = (ViewHolder) viewHolder;
synchronized (lock) {
@ -662,9 +701,10 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
holder.startUpdateTimer();
final Status status = statuses.get(i);
if (status == null)
return;
//TODO:It sounds that sometimes this value is null - need deeper investigation
if (status.getVisibility() == null) {
status.setVisibility("public");
@ -1301,6 +1341,38 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
status.setImageFound(true);
Status.makeImage(context, this, status);
}
if (instanceType != null && instanceType.compareTo("NITTER") == 0) {
holder.status_action_container.setVisibility(View.GONE);
if( holder.status_action_container_twitter != null){
holder.status_action_container_twitter.setVisibility(View.VISIBLE);
holder.status_action_container_twitter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.shared_via));
String url = status.getUrl();
String extra_text;
extra_text = (status.getReblog() != null) ? status.getReblog().getAccount().getAcct() : status.getAccount().getAcct();
if (extra_text.split("@").length == 1)
extra_text = "@" + extra_text + "@" + Helper.getLiveInstance(context);
else
extra_text = "@" + extra_text;
extra_text += " " + Helper.shortnameToUnicode(":link:", true) + " " + url + "\r\n-\n";
final String contentToot;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
contentToot = Html.fromHtml((status.getReblog() != null) ? status.getReblog().getContent() : status.getContent(), Html.FROM_HTML_MODE_LEGACY).toString();
else
//noinspection deprecation
contentToot = Html.fromHtml((status.getReblog() != null) ? status.getReblog().getContent() : status.getContent()).toString();
extra_text += contentToot;
sendIntent.putExtra(Intent.EXTRA_TEXT, extra_text);
sendIntent.setType("text/plain");
context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.share_with)));
}
});
}
}
holder.status_content.setOnTouchListener(new View.OnTouchListener() {
@Override
@ -1328,7 +1400,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
});
//Click on a conversation
if ((getItemViewType(viewHolder.getAdapterPosition()) == DISPLAYED_STATUS || getItemViewType(viewHolder.getAdapterPosition()) == COMPACT_STATUS || getItemViewType(viewHolder.getAdapterPosition()) == CONSOLE_STATUS)) {
if (( instanceType == null || instanceType.compareTo("NITTER") != 0) && (getItemViewType(viewHolder.getAdapterPosition()) == DISPLAYED_STATUS || getItemViewType(viewHolder.getAdapterPosition()) == COMPACT_STATUS || getItemViewType(viewHolder.getAdapterPosition()) == CONSOLE_STATUS)) {
holder.status_spoiler.setOnClickListener(new View.OnClickListener() {
@Override
@ -3152,7 +3224,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
}
});
} else {
} else if( instanceType == null || instanceType.compareTo("NITTER") != 0){
holder.status_account_profile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -3225,6 +3297,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
}
}
}
private void loadAttachments(final Status status, final ViewHolder holder, boolean blur) {
@ -4220,6 +4293,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
ConstraintLayout main_container;
TextView yandex_translate;
ConstraintLayout status_action_container;
ConstraintLayout status_action_container_twitter;
Button fetch_more;
ImageView new_element;
LinearLayout status_spoiler_mention_container;
@ -4325,6 +4399,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
yandex_translate = itemView.findViewById(R.id.yandex_translate);
new_element = itemView.findViewById(R.id.new_element);
status_action_container = itemView.findViewById(R.id.status_action_container);
status_action_container_twitter = itemView.findViewById(R.id.status_action_container_twitter);
status_spoiler_mention_container = itemView.findViewById(R.id.status_spoiler_mention_container);
status_mention_spoiler = itemView.findViewById(R.id.status_mention_spoiler);
status_cardview = itemView.findViewById(R.id.status_cardview);

View File

@ -206,7 +206,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
lastReadToot = sharedpreferences.getString(Helper.LAST_READ_TOOT_ID + userId + instance, null);
lastReadTootDate = Helper.stringToDate(context, sharedpreferences.getString(Helper.LAST_READ_TOOT_DATE + userId + instance, null));
}
if (instanceType == null || instanceType.equals("MASTODON") || instanceType.equals("MISSKEY") || instanceType.equals("GNU")) {
if (instanceType == null || instanceType.equals("MASTODON") || instanceType.equals("MISSKEY") || instanceType.equals("GNU") || instanceType.equals("NITTER")) {
if (type == RetrieveFeedsAsyncTask.Type.TAG && tag != null) {
BaseMainActivity.displayPeertube = null;
List<TagTimeline> tagTimelines = new SearchDAO(context, db).getTimelineInfo(tag);
@ -217,7 +217,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
}
} else {
BaseMainActivity.displayPeertube = null;
statusListAdapter = new StatusListAdapter(type, targetedId, isOnWifi, this.statuses);
statusListAdapter = new StatusListAdapter(instanceType, type, targetedId, isOnWifi, this.statuses);
lv_status.setAdapter(statusListAdapter);
}
} else if (instanceType.equals("PEERTUBE")) {
@ -580,7 +580,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
}
//Let's deal with statuses
if (statuses != null && statuses.size() > 0) {
if (statusListAdapter != null && (instanceType.equals("MASTODON") || instanceType.equals("MISSKEY") || instanceType.equals("GNU"))) {
if (statusListAdapter != null && (instanceType.equals("MASTODON") || instanceType.equals("NITTER") || instanceType.equals("MISSKEY") || instanceType.equals("GNU"))) {
this.statuses.addAll(statuses);
statusListAdapter.notifyItemRangeInserted(previousPosition, statuses.size());
} else if (artListAdapter != null && instanceType.equals("ART")) {
@ -863,6 +863,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
switch (instanceType) {
case "MASTODON":
case "MISSKEY":
case "NITTER":
case "GNU":
statusListAdapter.notifyItemRangeChanged(0, this.statuses.size());
break;
@ -892,7 +893,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
Status status = it.next();
for (Status status1 : statuses) {
if (status.getConversationId() != null && status.getConversationId().equals(status1.getConversationId())) {
if (instanceType.equals("MASTODON") || instanceType.equals("MISSKEY") || instanceType.equals("GNU"))
if (instanceType.equals("MASTODON") || instanceType.equals("MISSKEY") || instanceType.equals("NITTER")|| instanceType.equals("GNU"))
statusListAdapter.notifyItemRemoved(position);
else if (instanceType.equals("PIXELFED"))
pixelfedListAdapter.notifyItemRemoved(position);
@ -931,7 +932,8 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
}
}
}
if (statusListAdapter != null && (instanceType.equals("MASTODON") || instanceType.equals("MISSKEY") || instanceType.equals("GNU")))
if (statusListAdapter != null && (instanceType.equals("MASTODON") || instanceType.equals("MISSKEY") || instanceType.equals("NITTER") || instanceType.equals("GNU")))
statusListAdapter.notifyItemRangeInserted(0, inserted);
else if (pixelfedListAdapter != null && instanceType.equals("PIXELFED"))
pixelfedListAdapter.notifyItemRangeInserted(0, inserted);
@ -1158,6 +1160,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
switch (instanceType) {
case "MASTODON":
case "MISSKEY":
case "NITTER":
case "GNU":
statusListAdapter.notifyItemRangeRemoved(0, lenght);
break;

View File

@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="500"
android:viewportWidth="500" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#f00" android:pathData="M73.6,33.6L71,36.3v427.4l2.6,2.7 2.7,2.6h87.4l2.7,-2.6 2.6,-2.7L169,339.9c0,-102.6 0.2,-123.9 1.3,-123.9 0.8,0 41.1,56.1 89.7,124.7 48.5,68.7 89.2,125.6 90.4,126.5 1.9,1.6 5.5,1.8 37.7,1.8h35.6l2.7,-2.6 2.6,-2.7L429,36.3l-2.6,-2.7 -2.7,-2.6h-87.4l-2.7,2.6 -2.6,2.7v123.8c0,102.6 -0.2,123.9 -1.3,123.9 -0.8,0 -41.1,-56.1 -89.7,-124.8 -48.5,-68.6 -89.2,-125.5 -90.4,-126.4 -1.9,-1.6 -5.5,-1.8 -37.7,-1.8L76.3,31l-2.7,2.6zM232.5,180.7c51.2,72.3 94.4,133.1 96.1,134.9 2.9,3.1 3.6,3.4 9.1,3.4 5.2,0 6.4,-0.4 8.7,-2.6l2.6,-2.7L349,49h62v402l-25.2,-0.1h-25.3l-93,-131.6c-51.1,-72.3 -94.4,-133.1 -96.1,-134.9 -2.9,-3.1 -3.6,-3.4 -9.1,-3.4 -5.2,0 -6.4,0.4 -8.7,2.6l-2.6,2.7L151,451L89,451L89,49l25.3,0.1h25.2l93,131.6z"/>
</vector>

View File

@ -842,6 +842,24 @@
android:textStyle="italic"
android:visibility="gone" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/status_action_container_twitter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:id="@+id/status_share"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/ic_share_peertube"
android:tint="?attr/iconColor"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/status_action_container"
android:layout_width="match_parent"

View File

@ -48,5 +48,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/gnu_instance" />
<RadioButton
android:id="@+id/twitter_accounts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/twitter_accounts" />
</RadioGroup>
</LinearLayout>

View File

@ -1205,4 +1205,6 @@
<string name="action_trends">Trends</string>
<string name="trending_now">Trending now</string>
<string name="talking_about">%d people talking</string>
<string name="twitter_accounts">Twitter accounts</string>
<string name="list_of_twitter_accounts">Twitter usernames space separated</string>
</resources>