summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas <tschneider.ac@gmail.com>2022-06-27 18:16:41 +0200
committerThomas <tschneider.ac@gmail.com>2022-06-27 18:16:41 +0200
commit79d037036c1847ad2fc5b154de7b89b05236ea6d (patch)
treecf9bd8ccae892a2179fdd592ac83ec4d1070a82e
parente32101a6bb73558255368e31ef22b2f6ccd3b027 (diff)
Follow Peertube & Misskey instances
-rw-r--r--app/src/main/java/app/fedilab/android/activities/ReorderTimelinesActivity.java76
-rw-r--r--app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java33
-rw-r--r--app/src/main/java/app/fedilab/android/client/entities/misskey/MisskeyNote.java152
-rw-r--r--app/src/main/java/app/fedilab/android/client/entities/peertube/PeertubeVideo.java187
-rw-r--r--app/src/main/java/app/fedilab/android/helper/MastodonHelper.java28
-rw-r--r--app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java96
-rw-r--r--app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java3
-rw-r--r--app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java112
8 files changed, 639 insertions, 48 deletions
diff --git a/app/src/main/java/app/fedilab/android/activities/ReorderTimelinesActivity.java b/app/src/main/java/app/fedilab/android/activities/ReorderTimelinesActivity.java
index cde71cdf2..90a6c0cc0 100644
--- a/app/src/main/java/app/fedilab/android/activities/ReorderTimelinesActivity.java
+++ b/app/src/main/java/app/fedilab/android/activities/ReorderTimelinesActivity.java
@@ -19,6 +19,7 @@ import static app.fedilab.android.helper.PinnedTimelineHelper.sortMenuItem;
import static app.fedilab.android.helper.PinnedTimelineHelper.sortPositionAsc;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
@@ -37,6 +38,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -69,8 +71,10 @@ import app.fedilab.android.viewmodel.mastodon.ReorderVM;
import es.dmoral.toasty.Toasty;
import okhttp3.Call;
import okhttp3.Callback;
+import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
+import okhttp3.RequestBody;
import okhttp3.Response;
@@ -87,7 +91,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
private ActivityReorderTabsBinding binding;
private boolean changes;
private boolean bottomChanges;
-
+ private boolean update;
public void setChanges(boolean changes) {
this.changes = changes;
}
@@ -112,10 +116,12 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
bottomChanges = false;
ReorderVM reorderVM = new ViewModelProvider(ReorderTimelinesActivity.this).get(ReorderVM.class);
reorderVM.getPinned().observe(ReorderTimelinesActivity.this, _pinned -> {
+ update = true;
this.pinned = _pinned;
if (this.pinned == null) {
this.pinned = new Pinned();
this.pinned.pinnedTimelines = new ArrayList<>();
+ update = false;
}
sortPositionAsc(this.pinned.pinnedTimelines);
reorderTabAdapter = new ReorderTabAdapter(this.pinned, ReorderTimelinesActivity.this, ReorderTimelinesActivity.this);
@@ -153,7 +159,6 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
} else if (item.getItemId() == R.id.action_add_timeline) {
addInstance();
}
-
return super.onOptionsItemSelected(item);
}
@@ -168,11 +173,17 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ReorderTimelinesActivity.this, Helper.dialogStyle());
PopupSearchInstanceBinding popupSearchInstanceBinding = PopupSearchInstanceBinding.inflate(getLayoutInflater());
dialogBuilder.setView(popupSearchInstanceBinding.getRoot());
+ TextWatcher textWatcher = autoComplete(popupSearchInstanceBinding);
+ popupSearchInstanceBinding.searchInstance.addTextChangedListener(textWatcher);
+
popupSearchInstanceBinding.setAttachmentGroup.setOnCheckedChangeListener((group, checkedId) -> {
if (checkedId == R.id.twitter_accounts) {
popupSearchInstanceBinding.searchInstance.setHint(R.string.list_of_twitter_accounts);
+ popupSearchInstanceBinding.searchInstance.removeTextChangedListener(textWatcher);
} else {
popupSearchInstanceBinding.searchInstance.setHint(R.string.instance);
+ popupSearchInstanceBinding.searchInstance.removeTextChangedListener(textWatcher);
+ popupSearchInstanceBinding.searchInstance.addTextChangedListener(textWatcher);
}
});
popupSearchInstanceBinding.searchInstance.setFilters(new InputFilter[]{new InputFilter.LengthFilter(60)});
@@ -180,16 +191,24 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
String instanceName = popupSearchInstanceBinding.searchInstance.getText().toString().trim().replace("@", "");
new Thread(() -> {
String url = null;
- if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.mastodon_instance)
+ boolean getCall = true;
+ RequestBody formBody = new FormBody.Builder()
+ .build();
+ if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.mastodon_instance) {
url = "https://" + instanceName + "/api/v1/timelines/public?local=true";
- else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.peertube_instance)
+ } else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.peertube_instance) {
url = "https://" + instanceName + "/api/v1/videos/";
- else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.pixelfed_instance) {
+ } else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.pixelfed_instance) {
url = "https://" + instanceName + "/api/v1/timelines/public";
} else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.misskey_instance) {
url = "https://" + instanceName + "/api/notes/local-timeline";
+ getCall = false;
} else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.gnu_instance) {
url = "https://" + instanceName + "/api/statuses/public_timeline.json";
+ } else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.twitter_accounts) {
+ SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ReorderTimelinesActivity.this);
+ String nitterHost = sharedpreferences.getString(getString(R.string.SET_NITTER_HOST), getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase();
+ url = "https://" + nitterHost + "/" + instanceName.replaceAll("\\s", "") + "/rss";
}
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
@@ -198,9 +217,16 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
.readTimeout(10, TimeUnit.SECONDS).build();
Request request;
if (url != null) {
- request = new Request.Builder()
- .url(url)
- .build();
+ if (getCall) {
+ request = new Request.Builder()
+ .url(url)
+ .build();
+ } else {
+ request = new Request.Builder()
+ .url(url)
+ .post(formBody)
+ .build();
+ }
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
@@ -236,13 +262,26 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
pinnedTimeline.type = Timeline.TimeLineEnum.REMOTE;
pinnedTimeline.position = pinned.pinnedTimelines.size();
pinned.pinnedTimelines.add(pinnedTimeline);
- try {
- new Pinned(ReorderTimelinesActivity.this).updatePinned(pinned);
- changes = true;
- reorderTabAdapter.notifyItemInserted(pinned.pinnedTimelines.size());
- } catch (DBException e) {
- e.printStackTrace();
+
+ if (update) {
+ try {
+ new Pinned(ReorderTimelinesActivity.this).updatePinned(pinned);
+ } catch (DBException e) {
+ e.printStackTrace();
+ }
+ } else {
+ try {
+ new Pinned(ReorderTimelinesActivity.this).insertPinned(pinned);
+ } catch (DBException e) {
+ e.printStackTrace();
+ }
}
+ reorderTabAdapter.notifyItemInserted(pinned.pinnedTimelines.size());
+ Bundle b = new Bundle();
+ b.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
+ Intent intentBD = new Intent(Helper.BROADCAST_DATA);
+ intentBD.putExtras(b);
+ LocalBroadcastManager.getInstance(ReorderTimelinesActivity.this).sendBroadcast(intentBD);
});
} else {
runOnUiThread(() -> Toasty.warning(ReorderTimelinesActivity.this, getString(R.string.toast_instance_unavailable), Toast.LENGTH_LONG).show());
@@ -267,7 +306,11 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
popupSearchInstanceBinding.searchInstance.setOnItemClickListener((parent, view1, position, id) -> oldSearch = parent.getItemAtPosition(position).toString().trim());
- popupSearchInstanceBinding.searchInstance.addTextChangedListener(new TextWatcher() {
+
+ }
+
+ private TextWatcher autoComplete(PopupSearchInstanceBinding popupSearchInstanceBinding) {
+ return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@@ -314,8 +357,7 @@ public class ReorderTimelinesActivity extends BaseActivity implements OnStartDra
}
}
}
- });
-
+ };
}
@Override
diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java
index 01dfb83ff..69850f5bf 100644
--- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java
+++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java
@@ -21,12 +21,16 @@ import app.fedilab.android.client.entities.api.Conversation;
import app.fedilab.android.client.entities.api.Marker;
import app.fedilab.android.client.entities.api.MastodonList;
import app.fedilab.android.client.entities.api.Status;
+import app.fedilab.android.client.entities.misskey.MisskeyNote;
+import app.fedilab.android.client.entities.peertube.PeertubeVideo;
import retrofit2.Call;
+import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Header;
+import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
@@ -191,4 +195,33 @@ public interface MastodonTimelinesService {
@Field("home[last_read_id]") String home_last_read_id,
@Field("notifications[last_read_id]") String notifications_last_read_id
);
+
+
+ @Headers({"Accept: application/json"})
+ @POST("api/notes")
+ Call<List<MisskeyNote>> getMisskey(@Body MisskeyNote.MisskeyParams params);
+
+
+ //Public timelines for Misskey
+ @FormUrlEncoded
+ @POST("api/notes")
+ Call<List<MisskeyNote>> getMisskey(
+ @Field("local") boolean local,
+ @Field("file") boolean file,
+ @Field("poll") boolean poll,
+ @Field("remote") boolean remote,
+ @Field("reply") boolean reply,
+ @Field("untilId") String max_id,
+ @Field("since_id") String since_id,
+ @Field("limit") Integer limit
+ );
+
+ @GET("api/v1/videos")
+ Call<PeertubeVideo> getPeertube(
+ @Query("start") String start,
+ @Query("filter") String filter,
+ @Query("sort") String sort,
+ @Query("count") int count
+ );
+
}
diff --git a/app/src/main/java/app/fedilab/android/client/entities/misskey/MisskeyNote.java b/app/src/main/java/app/fedilab/android/client/entities/misskey/MisskeyNote.java
new file mode 100644
index 000000000..3b2bcda0e
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/client/entities/misskey/MisskeyNote.java
@@ -0,0 +1,152 @@
+package app.fedilab.android.client.entities.misskey;
+/* Copyright 2022 Thomas Schneider
+ *
+ * This file is a part of Fedilab
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Fedilab; if not,
+ * see <http://www.gnu.org/licenses>. */
+
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import app.fedilab.android.client.entities.api.Account;
+import app.fedilab.android.client.entities.api.Attachment;
+import app.fedilab.android.client.entities.api.Status;
+
+
+@SuppressWarnings("ALL")
+public class MisskeyNote implements Serializable {
+
+ @SerializedName("id")
+ public String id;
+ @SerializedName("createdAt")
+ public Date createdAt;
+ @SerializedName("replyId")
+ public String replyId;
+ @SerializedName("cw")
+ public String cw;
+ @SerializedName("text")
+ public String text;
+ @SerializedName("url")
+ public String url;
+ @SerializedName("uri")
+ public String uri;
+ @SerializedName("visibility")
+ public String visibility;
+ @SerializedName("repliesCount")
+ public int repliesCount;
+ @SerializedName("user")
+ public MisskeyUser user;
+ @SerializedName("files")
+ public List<MisskeyFile> files;
+ @SerializedName("emojis")
+ public List<MisskeyEmoji> emojis;
+
+ public static Status convert(MisskeyNote misskeyNote) {
+ Status status = new Status();
+ status.id = misskeyNote.id;
+ status.in_reply_to_id = misskeyNote.replyId;
+ status.content = misskeyNote.text != null ? misskeyNote.text : "";
+ status.text = misskeyNote.text != null ? misskeyNote.text : "";
+ status.spoiler_text = misskeyNote.cw;
+ status.visibility = misskeyNote.visibility;
+ status.created_at = misskeyNote.createdAt;
+ status.uri = misskeyNote.uri;
+ status.url = misskeyNote.url;
+
+ Account account = new Account();
+ account.id = misskeyNote.user.id;
+ account.acct = misskeyNote.user.username;
+ account.username = misskeyNote.user.username;
+ account.display_name = misskeyNote.user.name;
+ account.avatar = misskeyNote.user.avatarUrl;
+ account.avatar_static = misskeyNote.user.avatarUrl;
+ status.account = account;
+
+ if (misskeyNote.files != null && misskeyNote.files.size() > 0) {
+ List<Attachment> attachmentList = new ArrayList<>();
+ for (MisskeyFile misskeyFile : misskeyNote.files) {
+ Attachment attachment = new Attachment();
+ attachment.type = misskeyFile.type;
+ attachment.description = misskeyFile.comment;
+ attachment.url = misskeyFile.url;
+ attachment.preview_url = misskeyFile.thumbnailUrl;
+ if (misskeyFile.isSensitive) {
+ status.sensitive = true;
+ }
+ attachmentList.add(attachment);
+ }
+ status.media_attachments = attachmentList;
+ }
+
+ return status;
+ }
+
+ public static class MisskeyUser implements Serializable {
+ @SerializedName("id")
+ public String id;
+ @SerializedName("name")
+ public String name;
+ @SerializedName("username")
+ public String username;
+ @SerializedName("avatarUrl")
+ public String avatarUrl;
+ @SerializedName("emojis")
+ public List<MisskeyEmoji> emojis;
+ }
+
+ public static class MisskeyFile implements Serializable {
+ @SerializedName("id")
+ public String id;
+ @SerializedName("comment")
+ public String comment;
+ @SerializedName("isSensitive")
+ public boolean isSensitive;
+ @SerializedName("thumbnailUrl")
+ public String thumbnailUrl;
+ @SerializedName("url")
+ public String url;
+ @SerializedName("type")
+ public String type;
+ }
+
+ public static class MisskeyEmoji implements Serializable {
+ @SerializedName("name")
+ public String name;
+ @SerializedName("comment")
+ public String url;
+ }
+
+ public static class MisskeyParams implements Serializable {
+ @SerializedName("local")
+ public boolean local = true;
+ @SerializedName("file")
+ public boolean file = false;
+ @SerializedName("poll")
+ public boolean poll = false;
+ @SerializedName("remote")
+ public boolean remote = false;
+ @SerializedName("reply")
+ public boolean reply = false;
+ @SerializedName("max_id")
+ public String max_id;
+ @SerializedName("since_id")
+ public String since_id;
+ @SerializedName("limit")
+ public int limit;
+ }
+
+}
diff --git a/app/src/main/java/app/fedilab/android/client/entities/peertube/PeertubeVideo.java b/app/src/main/java/app/fedilab/android/client/entities/peertube/PeertubeVideo.java
new file mode 100644
index 000000000..90f323813
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/client/entities/peertube/PeertubeVideo.java
@@ -0,0 +1,187 @@
+package app.fedilab.android.client.entities.peertube;
+/* Copyright 2022 Thomas Schneider
+ *
+ * This file is a part of Fedilab
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Fedilab; if not,
+ * see <http://www.gnu.org/licenses>. */
+
+
+import com.google.gson.annotations.SerializedName;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import app.fedilab.android.client.entities.api.Account;
+import app.fedilab.android.client.entities.api.Attachment;
+import app.fedilab.android.client.entities.api.Status;
+
+@SuppressWarnings("ALL")
+public class PeertubeVideo implements Serializable {
+
+ @SerializedName("total")
+ public int total;
+ @SerializedName("data")
+ public List<Video> data;
+
+ public static Status convert(Video peertubeVideo) {
+ Status status = new Status();
+ status.id = peertubeVideo.id;
+ status.content = peertubeVideo.description != null ? peertubeVideo.description : "";
+ status.text = peertubeVideo.description;
+ status.visibility = "public";
+ status.created_at = peertubeVideo.publishedAt;
+ status.uri = peertubeVideo.uuid;
+ status.sensitive = peertubeVideo.nsfw;
+ status.url = "https://" + peertubeVideo.account.host + "/videos/watch/" + peertubeVideo.uuid;
+ Account account = new Account();
+ account.id = peertubeVideo.channel.id;
+ account.acct = peertubeVideo.channel.name;
+ account.username = peertubeVideo.channel.name;
+ account.display_name = peertubeVideo.channel.displayName;
+ if (peertubeVideo.channel.avatar != null) {
+ account.avatar = "https://" + peertubeVideo.account.host + peertubeVideo.channel.avatar.path;
+ account.avatar_static = "https://" + peertubeVideo.account.host + peertubeVideo.channel.avatar.path;
+ }
+ status.account = account;
+ List<Attachment> attachmentList = new ArrayList<>();
+ Attachment attachment = new Attachment();
+ attachment.type = "video/mp4";
+ attachment.url = "https://" + peertubeVideo.account.host + peertubeVideo.embedPath;
+ attachment.preview_url = "https://" + peertubeVideo.account.host + peertubeVideo.thumbnailPath;
+ attachmentList.add(attachment);
+ status.media_attachments = attachmentList;
+ return status;
+ }
+
+ public static class Video implements Serializable {
+ @SerializedName("account")
+ public PeertubeAccount account;
+ @SerializedName("category")
+ public Item category;
+ @SerializedName("channel")
+ public Channel channel;
+ @SerializedName("createdAt")
+ public Date createdAt;
+ @SerializedName("description")
+ public String description;
+ @SerializedName("duration")
+ public int duration;
+ @SerializedName("embedPath")
+ public String embedPath;
+ @SerializedName("id")
+ public String id;
+ @SerializedName("isLive")
+ public boolean isLive = false;
+ @SerializedName("url")
+ public String url;
+ @SerializedName("isLocal")
+ public boolean isLocal;
+ @SerializedName("language")
+ public ItemStr language;
+ @SerializedName("licence")
+ public Item licence;
+ @SerializedName("likes")
+ public int likes;
+ @SerializedName("name")
+ public String name;
+ @SerializedName("nsfw")
+ public boolean nsfw;
+ @SerializedName("originallyPublishedAt")
+ public Date originallyPublishedAt;
+ @SerializedName("previewPath")
+ public String previewPath;
+ @SerializedName("privacy")
+ public Item privacy;
+ @SerializedName("publishedAt")
+ public Date publishedAt;
+ @SerializedName("thumbnailPath")
+ public String thumbnailPath;
+ @SerializedName("updatedAt")
+ public Date updatedAt;
+ @SerializedName("uuid")
+ public String uuid;
+
+ @SerializedName("views")
+ public int views;
+ }
+
+ public static class PeertubeAccount implements Serializable {
+ @SerializedName("avatar")
+ public Avatar avatar;
+ @SerializedName("createdAt")
+ public Date createdAt;
+ @SerializedName("description")
+ public String description;
+ @SerializedName("displayName")
+ public String displayName;
+ @SerializedName("followersCount")
+ public int followersCount;
+ @SerializedName("followingCount")
+ public int followingCount;
+ @SerializedName("host")
+ public String host;
+ @SerializedName("hostRedundancyAllowed")
+ public boolean hostRedundancyAllowed;
+ @SerializedName("id")
+ public String id;
+ @SerializedName("name")
+ public String name;
+ @SerializedName("username")
+ public String username;
+ @SerializedName("updatedAt")
+ public Date updatedAt;
+ @SerializedName("url")
+ public String url;
+ @SerializedName("userId")
+ public String userId;
+ }
+
+ public static class Item implements Serializable {
+ @SerializedName("id")
+ public int id;
+ @SerializedName("label")
+ public String label;
+ }
+
+ public static class ItemStr implements Serializable {
+ @SerializedName("id")
+ public String id;
+ @SerializedName("label")
+ public String label;
+ }
+
+ public static class Channel implements Serializable {
+ @SerializedName("avatar")
+ public Avatar avatar;
+ @SerializedName("displayName")
+ public String displayName;
+ @SerializedName("host")
+ public String host;
+ @SerializedName("id")
+ public String id;
+ @SerializedName("name")
+ public String name;
+ @SerializedName("url")
+ public String url;
+ }
+
+ public static class Avatar implements Serializable {
+ @SerializedName("createdAt")
+ public Date createdAt;
+ @SerializedName("path")
+ public String path;
+ @SerializedName("updatedAt")
+ public Date updatedAt;
+ }
+}
diff --git a/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java b/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java
index 283473488..3c966a5f6 100644
--- a/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java
+++ b/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java
@@ -213,19 +213,27 @@ public class MastodonHelper {
return;
}
String targetedUrl = disableGif ? (type == MediaAccountType.AVATAR ? account.avatar_static : account.header_static) : (type == MediaAccountType.AVATAR ? account.avatar : account.header);
- if (disableGif || (!targetedUrl.endsWith(".gif"))) {
- Glide.with(view.getContext())
- .asDrawable()
- .load(targetedUrl)
- .thumbnail(0.1f)
- .placeholder(placeholder)
- .into(view);
+ if (targetedUrl != null) {
+ if (disableGif || (!targetedUrl.endsWith(".gif"))) {
+ Glide.with(view.getContext())
+ .asDrawable()
+ .load(targetedUrl)
+ .thumbnail(0.1f)
+ .placeholder(placeholder)
+ .into(view);
+ } else {
+ Glide.with(view.getContext())
+ .asGif()
+ .load(targetedUrl)
+ .thumbnail(0.1f)
+ .placeholder(placeholder)
+ .into(view);
+ }
} else {
Glide.with(view.getContext())
- .asGif()
- .load(targetedUrl)
+ .asDrawable()
+ .load(placeholder)
.thumbnail(0.1f)
- .placeholder(placeholder)
.into(view);
}
}
diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java
index 7eeeb17ae..618f5e205 100644
--- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java
+++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java
@@ -48,7 +48,9 @@ import app.fedilab.android.client.entities.api.Marker;
import app.fedilab.android.client.entities.api.Pagination;
import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.api.Statuses;
+import app.fedilab.android.client.entities.app.PinnedTimeline;
import app.fedilab.android.client.entities.app.QuickLoad;
+import app.fedilab.android.client.entities.app.RemoteInstance;
import app.fedilab.android.client.entities.app.TagTimeline;
import app.fedilab.android.client.entities.app.Timeline;
import app.fedilab.android.databinding.FragmentPaginationBinding;
@@ -136,6 +138,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
private Account accountTimeline;
private boolean exclude_replies, exclude_reblogs, show_pinned, media_only, minified;
private String viewModelKey, remoteInstance;
+ private PinnedTimeline pinnedTimeline;
private String ident;
private String instance, user_id;
private ArrayList<String> idOfAddedStatuses;
@@ -199,7 +202,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
list_id = getArguments().getString(Helper.ARG_LIST_ID, null);
search = getArguments().getString(Helper.ARG_SEARCH_KEYWORD, null);
searchCache = getArguments().getString(Helper.ARG_SEARCH_KEYWORD_CACHE, null);
- remoteInstance = getArguments().getString(Helper.ARG_REMOTE_INSTANCE, null);
+ pinnedTimeline = (PinnedTimeline) getArguments().getSerializable(Helper.ARG_REMOTE_INSTANCE);
+ if (pinnedTimeline != null && pinnedTimeline.remoteInstance != null) {
+ remoteInstance = pinnedTimeline.remoteInstance.host;
+ }
+
tagTimeline = (TagTimeline) getArguments().getSerializable(Helper.ARG_TAG_TIMELINE);
accountTimeline = (Account) getArguments().getSerializable(Helper.ARG_ACCOUNT);
exclude_replies = !getArguments().getBoolean(Helper.ARG_SHOW_REPLIES, true);
@@ -632,24 +639,75 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
});
}
} else if (timelineType == Timeline.TimeLineEnum.REMOTE) { //REMOTE TIMELINE
- if (direction == null) {
- timelinesVM.getPublic(null, remoteInstance, true, false, false, null, null, null, MastodonHelper.statusesPerCall(requireActivity()))
- .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
- } else if (direction == DIRECTION.BOTTOM) {
- timelinesVM.getPublic(null, remoteInstance, true, false, false, max_id, null, null, MastodonHelper.statusesPerCall(requireActivity()))
- .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false));
- } else if (direction == DIRECTION.TOP) {
- timelinesVM.getPublic(null, remoteInstance, true, false, false, null, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity()))
- .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing));
- } else if (direction == DIRECTION.REFRESH) {
- timelinesVM.getPublic(null, remoteInstance, true, false, false, null, null, null, MastodonHelper.statusesPerCall(requireActivity()))
- .observe(getViewLifecycleOwner(), statusesRefresh -> {
- if (statusAdapter != null) {
- dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
- } else {
- initializeStatusesCommonView(statusesRefresh);
- }
- });
+
+ //NITTER TIMELINES
+ if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) {
+
+ } //GNU TIMELINES
+ else if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.GNU) {
+
+ }//MISSKEY TIMELINES
+ else if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.MISSKEY) {
+ if (direction == null) {
+ timelinesVM.getMisskey(remoteInstance, null, null, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
+ } else if (direction == DIRECTION.BOTTOM) {
+ timelinesVM.getMisskey(remoteInstance, max_id, null, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false));
+ } else if (direction == DIRECTION.TOP) {
+ timelinesVM.getMisskey(remoteInstance, null, fetchingMissing ? min_id_fetch_more : min_id, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.TOP, fetchingMissing));
+ } else if (direction == DIRECTION.REFRESH) {
+ timelinesVM.getMisskey(remoteInstance, null, null, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), statusesRefresh -> {
+ if (statusAdapter != null) {
+ dealWithPagination(statusesRefresh, DIRECTION.REFRESH, true);
+ } else {
+ initializeStatusesCommonView(statusesRefresh);
+ }
+ });
+ }
+ } //PEERTUBE TIMELINES
+ else if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.PEERTUBE) {
+ if (direction == null) {
+
+ timelinesVM.getPeertube(remoteInstance, null, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
+ } else if (direction == DIRECTION.BOTTOM) {
+ timelinesVM.getPeertube(remoteInstance, max_id, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false));
+ } else if (direction == DIRECTION.TOP) {
+ flagLoading = false;
+ } else if (direction == DIRECTION.REFRESH) {
+ timelinesVM.getPeertube(remoteInstance, null, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), statusesRefresh -> {
+ if (statusAdapter != null) {
+ dealWithPagination(statusesRefresh