diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1b8f4706..9bf79691 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -265,6 +265,10 @@
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_about"
android:theme="@style/AppThemeBar" />
+
. */
+
+import android.os.Bundle;
+import android.view.MenuItem;
+
+import org.jetbrains.annotations.NotNull;
+
+import app.fedilab.android.R;
+import app.fedilab.android.databinding.ActivityTimelineBinding;
+import app.fedilab.android.mastodon.client.entities.app.PinnedTimeline;
+import app.fedilab.android.mastodon.client.entities.app.Timeline;
+import app.fedilab.android.mastodon.helper.Helper;
+import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
+
+
+public class TimelineActivity extends BaseBarActivity {
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ app.fedilab.android.databinding.ActivityTimelineBinding binding = ActivityTimelineBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+
+
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ }
+ Bundle b = getIntent().getExtras();
+ Timeline.TimeLineEnum timelineType = null;
+ String lemmy_post_id = null;
+ PinnedTimeline pinnedTimeline = null;
+ if (b != null) {
+ timelineType = (Timeline.TimeLineEnum) b.get(Helper.ARG_TIMELINE_TYPE);
+ lemmy_post_id = b.getString(Helper.ARG_LEMMY_POST_ID, null);
+ pinnedTimeline = (PinnedTimeline) b.getSerializable(Helper.ARG_REMOTE_INSTANCE);
+ }
+ if (pinnedTimeline != null && pinnedTimeline.remoteInstance != null) {
+ setTitle(pinnedTimeline.remoteInstance.displayName);
+ }
+ FragmentMastodonTimeline fragmentMastodonTimeline = new FragmentMastodonTimeline();
+ Bundle bundle = new Bundle();
+ bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, timelineType);
+ bundle.putSerializable(Helper.ARG_REMOTE_INSTANCE, pinnedTimeline);
+ bundle.putSerializable(Helper.ARG_LEMMY_POST_ID, lemmy_post_id);
+ fragmentMastodonTimeline.setArguments(bundle);
+
+ getSupportFragmentManager().beginTransaction()
+ .add(R.id.fragment_container_view, fragmentMastodonTimeline).commit();
+ }
+
+
+ @Override
+ public boolean onOptionsItemSelected(@NotNull MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+}
diff --git a/app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonTimelinesService.java b/app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonTimelinesService.java
index 3a014da0..f786199b 100644
--- a/app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonTimelinesService.java
+++ b/app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonTimelinesService.java
@@ -22,6 +22,7 @@ import app.fedilab.android.mastodon.client.entities.api.Marker;
import app.fedilab.android.mastodon.client.entities.api.MastodonList;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.api.Tag;
+import app.fedilab.android.mastodon.client.entities.lemmy.LemmyPost;
import app.fedilab.android.mastodon.client.entities.misskey.MisskeyNote;
import app.fedilab.android.mastodon.client.entities.nitter.Nitter;
import app.fedilab.android.mastodon.client.entities.peertube.PeertubeVideo;
@@ -230,6 +231,15 @@ public interface MastodonTimelinesService {
Call> getMisskey(@Body MisskeyNote.MisskeyParams params);
+ @GET("api/v3/post/list")
+ Call> getLemmyMain(@Query("limit") Integer limit,
+ @Query("page") String page);
+
+ @GET("api/v3/comment/list")
+ Call> getLemmyThread(@Query("post_id") String post_id,
+ @Query("limit") Integer limit,
+ @Query("page") String page);
+
//Public timelines for Misskey
@FormUrlEncoded
@POST("api/notes")
diff --git a/app/src/main/java/app/fedilab/android/mastodon/helper/Helper.java b/app/src/main/java/app/fedilab/android/mastodon/helper/Helper.java
index 368c493d..6d331a37 100644
--- a/app/src/main/java/app/fedilab/android/mastodon/helper/Helper.java
+++ b/app/src/main/java/app/fedilab/android/mastodon/helper/Helper.java
@@ -259,6 +259,8 @@ public class Helper {
public static final String ARG_STATUS_ID = "ARG_STATUS_ID";
public static final String ARG_WORK_ID = "ARG_WORK_ID";
public static final String ARG_LIST_ID = "ARG_LIST_ID";
+ public static final String ARG_LEMMY_POST_ID = "ARG_LEMMY_POST_ID";
+
public static final String ARG_SEARCH_KEYWORD = "ARG_SEARCH_KEYWORD";
public static final String ARG_DIRECTORY_ORDER = "ARG_DIRECTORY_ORDER";
public static final String ARG_DIRECTORY_LOCAL = "ARG_DIRECTORY_LOCAL";
diff --git a/app/src/main/java/app/fedilab/android/mastodon/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/mastodon/helper/PinnedTimelineHelper.java
index 1a44a19e..998ec2d0 100644
--- a/app/src/main/java/app/fedilab/android/mastodon/helper/PinnedTimelineHelper.java
+++ b/app/src/main/java/app/fedilab/android/mastodon/helper/PinnedTimelineHelper.java
@@ -370,7 +370,9 @@ public class PinnedTimelineHelper {
case MASTODON:
tabCustomViewBinding.icon.setImageResource(R.drawable.mastodon_icon_item);
break;
-
+ case LEMMY:
+ tabCustomViewBinding.icon.setImageResource(R.drawable.lemmy);
+ break;
case MISSKEY:
tabCustomViewBinding.icon.setImageResource(R.drawable.misskey);
break;
@@ -461,6 +463,9 @@ public class PinnedTimelineHelper {
case MISSKEY:
item.setIcon(R.drawable.misskey);
break;
+ case LEMMY:
+ item.setIcon(R.drawable.lemmy);
+ break;
case PIXELFED:
item.setIcon(R.drawable.pixelfed);
break;
diff --git a/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java
index bebbeba4..187ca79c 100644
--- a/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java
+++ b/app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java
@@ -139,6 +139,7 @@ import app.fedilab.android.mastodon.activities.ProfileActivity;
import app.fedilab.android.mastodon.activities.ReportActivity;
import app.fedilab.android.mastodon.activities.StatusHistoryActivity;
import app.fedilab.android.mastodon.activities.StatusInfoActivity;
+import app.fedilab.android.mastodon.activities.TimelineActivity;
import app.fedilab.android.mastodon.activities.admin.AdminAccountActivity;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Poll;
@@ -146,6 +147,8 @@ import app.fedilab.android.mastodon.client.entities.api.Reaction;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.app.Account;
import app.fedilab.android.mastodon.client.entities.app.BaseAccount;
+import app.fedilab.android.mastodon.client.entities.app.PinnedTimeline;
+import app.fedilab.android.mastodon.client.entities.app.RemoteInstance;
import app.fedilab.android.mastodon.client.entities.app.StatusCache;
import app.fedilab.android.mastodon.client.entities.app.StatusDraft;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
@@ -187,6 +190,9 @@ public class StatusAdapter extends RecyclerView.Adapter
private final List statusList;
private final boolean minified;
private final Timeline.TimeLineEnum timelineType;
+ public RemoteInstance.InstanceType type;
+ public String lemmy_post_id;
+ public PinnedTimeline pinnedTimeline;
private final boolean canBeFederated;
private final boolean checkRemotely;
public FetchMoreCallBack fetchMoreCallBack;
@@ -1989,7 +1995,18 @@ public class StatusAdapter extends RecyclerView.Adapter
((ContextActivity) context).setCurrentFragment((FragmentMastodonContext) fragment);
} else {
if (remote) {
- if (!(context instanceof ContextActivity)) { //We are not already checking a remote conversation
+ //Lemmy main post that should open Lemmy threads
+ if (adapter instanceof StatusAdapter && ((StatusAdapter) adapter).type == RemoteInstance.InstanceType.LEMMY && ((StatusAdapter) adapter).lemmy_post_id == null) {
+ Bundle bundle = new Bundle();
+ bundle.putSerializable(Helper.ARG_REMOTE_INSTANCE, ((StatusAdapter) adapter).pinnedTimeline);
+ bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.REMOTE);
+ bundle.putSerializable(Helper.ARG_LEMMY_POST_ID, ((StatusAdapter) adapter).lemmy_post_id);
+ Intent intent = new Intent(context, TimelineActivity.class);
+ intent.putExtras(bundle);
+ context.startActivity(intent);
+
+ } //Classic other cases for remote instances that will search the remote context
+ else if (!(context instanceof ContextActivity)) { //We are not already checking a remote conversation
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
.observe((LifecycleOwner) context, results -> {
diff --git a/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java
index 07e87bfd..a5f86e03 100644
--- a/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java
+++ b/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java
@@ -89,6 +89,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
private List timelineStatuses;
private boolean retry_for_home_done;
+ private String lemmy_post_id;
//Handle actions that can be done in other fragments
private final BroadcastReceiver receive_action = new BroadcastReceiver() {
@@ -382,6 +383,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
retry_for_home_done = false;
if (getArguments() != null) {
timelineType = (Timeline.TimeLineEnum) getArguments().get(Helper.ARG_TIMELINE_TYPE);
+ lemmy_post_id = getArguments().getString(Helper.ARG_LEMMY_POST_ID, null);
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);
@@ -625,6 +627,14 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
}
statusAdapter = new StatusAdapter(timelineStatuses, timelineType, minified, canBeFederated, checkRemotely);
statusAdapter.fetchMoreCallBack = this;
+ statusAdapter.pinnedTimeline = pinnedTimeline;
+ //------Specifications for Lemmy timelines
+ if (pinnedTimeline != null && pinnedTimeline.remoteInstance != null) {
+ statusAdapter.type = pinnedTimeline.remoteInstance.type;
+ }
+ statusAdapter.lemmy_post_id = lemmy_post_id;
+ //---------------
+
if (statusReport != null) {
scrollToTop();
}
@@ -1019,7 +1029,27 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
}
});
}
- } //PEERTUBE TIMELINES
+ } //LEMMY TIMELINES
+ else if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.LEMMY) {
+ if (direction == null) {
+ timelinesVM.getLemmy(remoteInstance, lemmy_post_id, null, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
+ } else if (direction == DIRECTION.BOTTOM) {
+ timelinesVM.getLemmy(remoteInstance, lemmy_post_id, max_id, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
+ } else if (direction == DIRECTION.TOP) {
+ flagLoading = false;
+ } else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
+ timelinesVM.getLemmy(remoteInstance, lemmy_post_id, null, MastodonHelper.statusesPerCall(requireActivity()))
+ .observe(getViewLifecycleOwner(), statusesRefresh -> {
+ if (statusAdapter != null) {
+ dealWithPagination(statusesRefresh, direction, true, true, fetchStatus);
+ } 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()))
diff --git a/app/src/main/java/app/fedilab/android/mastodon/viewmodel/mastodon/TimelinesVM.java b/app/src/main/java/app/fedilab/android/mastodon/viewmodel/mastodon/TimelinesVM.java
index 55800510..64abd972 100644
--- a/app/src/main/java/app/fedilab/android/mastodon/viewmodel/mastodon/TimelinesVM.java
+++ b/app/src/main/java/app/fedilab/android/mastodon/viewmodel/mastodon/TimelinesVM.java
@@ -52,6 +52,7 @@ import app.fedilab.android.mastodon.client.entities.app.BaseAccount;
import app.fedilab.android.mastodon.client.entities.app.StatusCache;
import app.fedilab.android.mastodon.client.entities.app.StatusDraft;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
+import app.fedilab.android.mastodon.client.entities.lemmy.LemmyPost;
import app.fedilab.android.mastodon.client.entities.misskey.MisskeyNote;
import app.fedilab.android.mastodon.client.entities.nitter.Nitter;
import app.fedilab.android.mastodon.client.entities.peertube.PeertubeVideo;
@@ -335,6 +336,60 @@ public class TimelinesVM extends AndroidViewModel {
return statusesMutableLiveData;
}
+ /**
+ * Public timeline for Lemmy
+ *
+ * @param post_id Return comments for post_id, if null it's for main threads
+ * @param page Return results from this page
+ * @param limit Maximum number of results to return. Defaults to 20.
+ * @return {@link LiveData} containing a {@link Statuses}
+ */
+ public LiveData getLemmy(@NonNull String instance, String post_id,
+ String page,
+ Integer limit) {
+ MastodonTimelinesService mastodonTimelinesService = initInstanceOnly(instance);
+ statusesMutableLiveData = new MutableLiveData<>();
+ new Thread(() -> {
+
+ Call> publicTlCall;
+ if (post_id == null) {
+ publicTlCall = mastodonTimelinesService.getLemmyMain(limit, page);
+ } else {
+ publicTlCall = mastodonTimelinesService.getLemmyThread(post_id, limit, page);
+ }
+ Statuses statuses = new Statuses();
+ if (publicTlCall != null) {
+ try {
+ Response> publicTlResponse = publicTlCall.execute();
+ if (publicTlResponse.isSuccessful()) {
+ List lemmyPostList = publicTlResponse.body();
+ List statusList = new ArrayList<>();
+ if (lemmyPostList != null) {
+ for (LemmyPost lemmyPost : lemmyPostList) {
+ Status status = LemmyPost.convert(lemmyPost, instance);
+ statusList.add(status);
+ }
+ }
+ statuses.statuses = TimelineHelper.filterStatus(getApplication(), statusList, Timeline.TimeLineEnum.PUBLIC);
+ statuses.pagination = new Pagination();
+ if (statusList.size() > 0) {
+ statuses.pagination.min_id = statusList.get(0).id;
+ statuses.pagination.max_id = statusList.get(statusList.size() - 1).id;
+ }
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ Runnable myRunnable = () -> statusesMutableLiveData.setValue(statuses);
+ mainHandler.post(myRunnable);
+ }).start();
+ return statusesMutableLiveData;
+ }
+
+
/**
* Public timeline for Peertube
*
diff --git a/app/src/main/res/layouts/mastodon/drawable/baseline_exit_to_app_24.xml b/app/src/main/res/drawables/mastodon/drawable/baseline_exit_to_app_24.xml
similarity index 100%
rename from app/src/main/res/layouts/mastodon/drawable/baseline_exit_to_app_24.xml
rename to app/src/main/res/drawables/mastodon/drawable/baseline_exit_to_app_24.xml
diff --git a/app/src/main/res/drawables/mastodon/drawable/baseline_live_tv_24.xml b/app/src/main/res/drawables/mastodon/drawable/baseline_live_tv_24.xml
new file mode 100644
index 00000000..fc5ca9b3
--- /dev/null
+++ b/app/src/main/res/drawables/mastodon/drawable/baseline_live_tv_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layouts/mastodon/drawable/baseline_ondemand_video_24.xml b/app/src/main/res/drawables/mastodon/drawable/baseline_ondemand_video_24.xml
similarity index 100%
rename from app/src/main/res/layouts/mastodon/drawable/baseline_ondemand_video_24.xml
rename to app/src/main/res/drawables/mastodon/drawable/baseline_ondemand_video_24.xml
diff --git a/app/src/main/res/layouts/mastodon/drawable/baseline_show_chart_24.xml b/app/src/main/res/drawables/mastodon/drawable/baseline_show_chart_24.xml
similarity index 100%
rename from app/src/main/res/layouts/mastodon/drawable/baseline_show_chart_24.xml
rename to app/src/main/res/drawables/mastodon/drawable/baseline_show_chart_24.xml
diff --git a/app/src/main/res/layouts/mastodon/drawable/lemmy.xml b/app/src/main/res/drawables/mastodon/drawable/lemmy.xml
similarity index 100%
rename from app/src/main/res/layouts/mastodon/drawable/lemmy.xml
rename to app/src/main/res/drawables/mastodon/drawable/lemmy.xml
diff --git a/app/src/main/res/layouts/mastodon/drawable/lemmy_logo.xml b/app/src/main/res/drawables/mastodon/drawable/lemmy_logo.xml
similarity index 100%
rename from app/src/main/res/layouts/mastodon/drawable/lemmy_logo.xml
rename to app/src/main/res/drawables/mastodon/drawable/lemmy_logo.xml
diff --git a/app/src/main/res/layouts/mastodon/layout/activity_timeline.xml b/app/src/main/res/layouts/mastodon/layout/activity_timeline.xml
new file mode 100644
index 00000000..a7671224
--- /dev/null
+++ b/app/src/main/res/layouts/mastodon/layout/activity_timeline.xml
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file