Following Misskey - step 1

This commit is contained in:
stom79 2018-12-29 12:09:02 +01:00
parent 2ed70688b9
commit 4c00ba823b
14 changed files with 297 additions and 8 deletions

View File

@ -409,8 +409,9 @@ public abstract class BaseMainActivity extends BaseActivity
SubMenu submMastodon = popup.getMenu().findItem(R.id.action_show_mastodon).getSubMenu();
SubMenu submPeertube = popup.getMenu().findItem(R.id.action_show_peertube).getSubMenu();
SubMenu submPixelfed = popup.getMenu().findItem(R.id.action_show_pixelfed).getSubMenu();
SubMenu submMisskey = popup.getMenu().findItem(R.id.action_show_misskey).getSubMenu();
SubMenu submChannel = popup.getMenu().findItem(R.id.action_show_channel).getSubMenu();
int i = 0, j = 0 , k = 0;
int i = 0, j = 0 , k = 0, l = 0 , m = 0;
for (RemoteInstance remoteInstance : remoteInstances) {
if (remoteInstance.getType() == null || remoteInstance.getType().equals("MASTODON")) {
MenuItem itemPlaceHolder = submMastodon.findItem(R.id.mastodon_instances);
@ -506,11 +507,42 @@ public abstract class BaseMainActivity extends BaseActivity
});
j++;
}
if (remoteInstance.getType() == null || remoteInstance.getType().equals("MISSKEY")) {
MenuItem itemPlaceHolder = submPixelfed.findItem(R.id.misskey_instance);
if( itemPlaceHolder != null)
itemPlaceHolder.setVisible(false);
MenuItem item = submMisskey.add(0, l, Menu.NONE, remoteInstance.getHost());
item.setIcon(R.drawable.misskey);
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
DisplayStatusFragment statusFragment;
Bundle bundle = new Bundle();
statusFragment = new DisplayStatusFragment();
bundle.putSerializable("type", RetrieveFeedsAsyncTask.Type.REMOTE_INSTANCE);
bundle.putString("remote_instance", remoteInstance.getHost());
statusFragment.setArguments(bundle);
String fragmentTag = "REMOTE_INSTANCE";
instance_id = remoteInstance.getDbID();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.main_app_container, statusFragment, fragmentTag).commit();
main_app_container.setVisibility(View.VISIBLE);
viewPager.setVisibility(View.GONE);
tabLayout.setVisibility(View.GONE);
toolbarTitle.setVisibility(View.VISIBLE);
delete_instance.setVisibility(View.VISIBLE);
toolbarTitle.setText(remoteInstance.getHost());
return false;
}
});
l++;
}
if (remoteInstance.getType() == null || remoteInstance.getType().equals("PEERTUBE")) {
MenuItem itemPlaceHolder = submPeertube.findItem(R.id.peertube_instances);
if( itemPlaceHolder != null)
itemPlaceHolder.setVisible(false);
MenuItem item = submPeertube.add(0, j, Menu.NONE, remoteInstance.getHost());
MenuItem item = submPeertube.add(0, m, Menu.NONE, remoteInstance.getHost());
item.setIcon(R.drawable.peertube_icon);
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
@ -535,7 +567,7 @@ public abstract class BaseMainActivity extends BaseActivity
return false;
}
});
j++;
m++;
}
}
}
@ -568,6 +600,8 @@ public abstract class BaseMainActivity extends BaseActivity
new HttpsConnection(BaseMainActivity.this).get("https://" + instanceName + "/api/v1/videos/", 10, null, null);
else if( radioGroup.getCheckedRadioButtonId() == R.id.pixelfed_instance) {
new HttpsConnection(BaseMainActivity.this).get("https://" + instanceName + "/api/v1/timelines/public", 10, null, null);
}else if( radioGroup.getCheckedRadioButtonId() == R.id.misskey_instance) {
new HttpsConnection(BaseMainActivity.this).post("https://" + instanceName + "/api/notes/local-timeline", 10, null, null);
}
runOnUiThread(new Runnable() {
public void run() {
@ -579,6 +613,8 @@ public abstract class BaseMainActivity extends BaseActivity
new InstancesDAO(BaseMainActivity.this, db).insertInstance(instanceName, "PEERTUBE");
else if( radioGroup.getCheckedRadioButtonId() == R.id.pixelfed_instance)
new InstancesDAO(BaseMainActivity.this, db).insertInstance(instanceName, "PIXELFED");
else if( radioGroup.getCheckedRadioButtonId() == R.id.misskey_instance)
new InstancesDAO(BaseMainActivity.this, db).insertInstance(instanceName, "MISSKEY");
DisplayStatusFragment statusFragment;
Bundle bundle = new Bundle();
statusFragment = new DisplayStatusFragment();

View File

@ -176,7 +176,15 @@ public class RetrieveFeedsAsyncTask extends AsyncTask<Void, Void, Void> {
status.setType(action);
}
}
}else {
}else if(remoteInstanceObj != null && remoteInstanceObj.size() > 0 && remoteInstanceObj.get(0).getType().equals("MISSKEY")){
apiResponse = api.getMisskey(this.instanceName, max_id);
List<fr.gouv.etalab.mastodon.client.Entities.Status> statusesTemp = apiResponse.getStatuses();
if( statusesTemp != null){
for(fr.gouv.etalab.mastodon.client.Entities.Status status: statusesTemp){
status.setType(action);
}
}
} else {
apiResponse = api.getPeertube(this.instanceName, max_id);
}
}

View File

@ -17,6 +17,7 @@ package fr.gouv.etalab.mastodon.client;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
@ -1039,6 +1040,39 @@ public class API {
apiResponse.setHowToVideos(howToVideos);
return apiResponse;
}
/**
* Retrieves Peertube videos from an instance *synchronously*
* @return APIResponse
*/
public APIResponse getMisskey(String instance, String max_id) {
HashMap<String, String> params = new HashMap<>();
if( max_id != null)
params.put("untilId",max_id);
try {
statuses = new ArrayList<>();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.post(String.format("https://"+instance+"/api/notes/local-timeline", max_id), 60, params, null);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
statuses = parseNotes(context, instance, new JSONArray(response));
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
apiResponse.setStatuses(statuses);
return apiResponse;
}
/**
* Retrieves public timeline for the account *synchronously*
* @param local boolean only local timeline
@ -3134,6 +3168,150 @@ public class API {
return status;
}
/**
* Parse json response for several notes (Misskey)
* @param jsonArray JSONArray
* @return List<Status>
*/
public static List<Status> parseNotes(Context context, String instance, JSONArray jsonArray){
List<Status> statuses = new ArrayList<>();
try {
int i = 0;
while (i < jsonArray.length() ){
JSONObject resobj = jsonArray.getJSONObject(i);
Status status = parseNotes(context, instance, resobj);
i++;
statuses.add(status);
}
} catch (JSONException e) {
e.printStackTrace();
}
return statuses;
}
/**
* Parse json response for unique note (misskey)
* @param resobj JSONObject
* @return Status
*/
@SuppressWarnings("InfiniteRecursion")
public static Status parseNotes(Context context, String instance, JSONObject resobj){
Status status = new Status();
try {
status.setId(resobj.get("id").toString());
status.setUri("https://" + instance + "/notes/" + resobj.get("id").toString());
status.setCreated_at(Helper.mstStringToDate(context, resobj.get("createdAt").toString()));
status.setIn_reply_to_id(resobj.get("replyId").toString());
status.setSensitive(false);
if(resobj.get("cw") != null && !resobj.get("cw").toString().equals("null"))
status.setSpoiler_text(resobj.get("cw").toString());
try {
status.setVisibility(resobj.get("visibility").toString());
}catch (Exception e){status.setVisibility("public"); e.printStackTrace();}
status.setUrl("https://" + instance + "/notes/" + resobj.get("id").toString());
//Retrieves attachments
JSONArray arrayAttachement = resobj.getJSONArray("media");
ArrayList<Attachment> attachments = new ArrayList<>();
if( arrayAttachement != null){
for(int j = 0 ; j < arrayAttachement.length() ; j++){
JSONObject attObj = arrayAttachement.getJSONObject(j);
Attachment attachment = new Attachment();
attachment.setId(attObj.get("id").toString());
attachment.setPreview_url(attObj.get("thumbnailUrl").toString());
attachment.setRemote_url(attObj.get("url").toString());
if( attObj.get("type").toString().contains("/")){
attachment.setType(attObj.get("type").toString().split("/")[0]);
}else
attachment.setType(attObj.get("type").toString());
attachment.setText_url(attObj.get("url").toString());
attachment.setUrl(attObj.get("url").toString());
if(attObj.get("isSensitive").toString().equals("true")){
status.setSensitive(true);
}
try {
attachment.setDescription(attObj.get("comment").toString());
}catch (JSONException ignore){ignore.printStackTrace();}
attachments.add(attachment);
}
}
try {
status.setCard(parseCardResponse(resobj.getJSONObject("card")));
}catch (Exception e){status.setCard(null);}
status.setMedia_attachments(attachments);
//Retrieves mentions
List<Mention> mentions = new ArrayList<>();
status.setAccount(parseMisskeyAccountResponse(context, instance, resobj.getJSONObject("user")));
status.setContent(resobj.get("text").toString());
try{
status.setReplies_count(Integer.valueOf(resobj.get("repliesCount").toString()));
}catch (Exception e){
status.setReplies_count(-1);
}
try {
status.setFavourited(Boolean.valueOf(resobj.get("isFavorited").toString()));
}catch (Exception e){
status.setFavourited(false);
}
try{
if(resobj.getJSONObject("renoteId") != null && !resobj.getJSONObject("renoteId").toString().equals("null"))
status.setReblog(parseStatuses(context, resobj.getJSONObject("renote")));
}catch (Exception ignored){}
status.setMentions(mentions);
//Retrieves tags
List<Tag> tags = new ArrayList<>();
JSONArray arrayTag = resobj.getJSONArray("tags");
if( arrayTag != null){
for(int j = 0 ; j < arrayTag.length() ; j++){
JSONObject tagObj = arrayTag.getJSONObject(j);
Tag tag = new Tag();
tag.setName(tagObj.get("name").toString());
tag.setUrl(tagObj.get("url").toString());
tags.add(tag);
}
}
status.setTags(tags);
//Retrieves emjis
List<Emojis> emojiList = new ArrayList<>();
try {
JSONArray emojisTag = resobj.getJSONArray("emojis");
if( emojisTag != null){
for(int j = 0 ; j < emojisTag.length() ; j++){
JSONObject emojisObj = emojisTag.getJSONObject(j);
Emojis emojis = parseEmojis(emojisObj);
emojiList.add(emojis);
}
}
status.setEmojis(emojiList);
}catch (Exception e){
status.setEmojis(new ArrayList<>());
}
//Retrieve Application
Application application = new Application();
try {
if(resobj.getJSONObject("application") != null){
application.setName(resobj.getJSONObject("application").getString("name"));
application.setWebsite(resobj.getJSONObject("application").getString("website"));
}
}catch (Exception e){
application = new Application();
}
status.setApplication(application);
} catch (JSONException ignored) {} catch (ParseException e) {
e.printStackTrace();
}
return status;
}
/**
* Parse json response an unique instance
* @param resobj JSONObject
@ -3421,6 +3599,56 @@ public class API {
return account;
}
/**
* Parse json response an unique account
* @param resobj JSONObject
* @return Account
*/
@SuppressWarnings("InfiniteRecursion")
private static Account parseMisskeyAccountResponse(Context context, String instance, JSONObject resobj){
Log.v(Helper.TAG,"resobj= " + resobj);
Account account = new Account();
try {
account.setId(resobj.get("id").toString());
account.setUsername(resobj.get("username").toString());
String host = resobj.get("host").toString();
String acct;
if( host == null || host.equals("null"))
acct = resobj.get("username").toString();
else
acct = resobj.get("username").toString() + "@" + host;
account.setAcct(acct);
account.setDisplay_name(resobj.get("name").toString());
account.setCreated_at(new Date());
account.setUrl("https://" + instance + "/@"+account.getUsername());
account.setAvatar(resobj.get("avatarUrl").toString());
account.setAvatar_static(resobj.get("avatarUrl").toString());
try {
account.setBot(Boolean.parseBoolean(resobj.get("isBot").toString()));
}catch (Exception e){
account.setBot(false);
}
//Retrieves emjis
List<Emojis> emojiList = new ArrayList<>();
try {
JSONArray emojisTag = resobj.getJSONArray("emojis");
if( emojisTag != null){
for(int j = 0 ; j < emojisTag.length() ; j++){
JSONObject emojisObj = emojisTag.getJSONObject(j);
Emojis emojis = parseEmojis(emojisObj);
emojiList.add(emojis);
}
}
account.setEmojis(emojiList);
}catch (Exception e){
account.setEmojis(new ArrayList<>());
}
} catch (JSONException ignored) {}
return account;
}
/**
* Parse json response for list of accounts
* @param jsonArray JSONArray

View File

@ -437,7 +437,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
boolean isCompactMode = sharedpreferences.getBoolean(Helper.SET_COMPACT_MODE, false);
if( type == RetrieveFeedsAsyncTask.Type.CONTEXT && position == conversationPosition)
return FOCUSED_STATUS;
else if( !Helper.filterToots(context, statuses.get(position), timedMute, type))
else if( type != RetrieveFeedsAsyncTask.Type.REMOTE_INSTANCE && !Helper.filterToots(context, statuses.get(position), timedMute, type))
return HIDDEN_STATUS;
else
return isCompactMode?COMPACT_STATUS:DISPLAYED_STATUS;
@ -1091,8 +1091,8 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
}
holder.status_mention_spoiler.setText(Helper.makeMentionsClick(context,status.getMentions()), TextView.BufferType.SPANNABLE);
if( status.getMentions() != null)
holder.status_mention_spoiler.setText(Helper.makeMentionsClick(context,status.getMentions()), TextView.BufferType.SPANNABLE);
holder.status_mention_spoiler.setMovementMethod(LinkMovementMethod.getInstance());
if( getItemViewType(viewHolder.getAdapterPosition()) != COMPACT_STATUS ) {

View File

@ -179,7 +179,7 @@ public class DisplayStatusFragment extends Fragment implements OnRetrieveFeedsIn
statusListAdapter = new StatusListAdapter(context, tagTimeline, targetedId, isOnWifi, this.statuses);
lv_status.setAdapter(statusListAdapter);
}
}else if( search_peertube == null && (instanceType == null || instanceType.equals("MASTODON") || instanceType.equals("PIXELFED"))) {
}else if( search_peertube == null && (instanceType == null || instanceType.equals("MASTODON") || instanceType.equals("PIXELFED") || instanceType.equals("MISSKEY"))) {
BaseMainActivity.displayPeertube = null;
if( instanceType != null && instanceType.equals("PIXELFED"))
type = RetrieveFeedsAsyncTask.Type.PIXELFED;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -31,5 +31,10 @@
android:layout_height="wrap_content"
android:text="@string/pixelfed_instance"
/>
<RadioButton android:id="@+id/misskey_instance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/misskey_instance"
/>
</RadioGroup>
</LinearLayout>

View File

@ -37,6 +37,16 @@
<item android:id="@+id/pixelfed_instance" android:title="@string/no_pixelfed_instance"/>
</menu>
</item>
<item
android:id="@+id/action_show_misskey"
android:title="Misskey"
android:icon="@drawable/misskey"
app:showAsAction="never"
>
<menu>
<item android:id="@+id/misskey_instance" android:title="@string/no_misskey_instance"/>
</menu>
</item>
<item
android:id="@+id/action_show_channel"
android:title="@string/channel"

View File

@ -784,6 +784,8 @@
<string name="some_words_all">All these words (space-separated)</string>
<string name="some_words_none">None of these words (space-separated)</string>
<string name="change_tag_column">Change column name</string>
<string name="no_misskey_instance">No Misskey instances</string>
<string name="misskey_instance">Misskey instance</string>
<!-- end languages -->
</resources>