Show announcements

This commit is contained in:
kyori19 2020-01-28 01:11:10 +09:00
parent 18f859e43e
commit bf5e0a4b81
12 changed files with 243 additions and 9 deletions

View File

@ -209,7 +209,7 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
viewPager = findViewById(R.id.pager);
ConstraintLayout quickTootContainer = findViewById(R.id.quick_toot_container);
QuickTootHelper quickTootHelper = new QuickTootHelper(quickTootContainer, accountManager, eventHub);
QuickTootHelper quickTootHelper = new QuickTootHelper(this, quickTootContainer, accountManager, eventHub);
composeButton.setOnClickListener(v -> quickTootHelper.composeButton());
tabLayout.requestFocus();

View File

@ -64,7 +64,7 @@ class ModalTimelineActivity : BottomSheetActivity(), ActionButtonActivity, HasAn
val quickTootContainer = findViewById<ConstraintLayout>(R.id.quick_toot_container)
val composeButton = findViewById<FloatingActionButton>(R.id.floating_btn)
val quickTootHelper = QuickTootHelper(quickTootContainer, accountManager, eventHub)
val quickTootHelper = QuickTootHelper(this, quickTootContainer, accountManager, eventHub)
eventHub.events
.observeOn(AndroidSchedulers.mainThread())

View File

@ -24,14 +24,10 @@ import androidx.fragment.app.commit
import androidx.lifecycle.Lifecycle
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.fragment.TimelineFragment
import com.keylesspalace.tusky.fragment.TimelineFragment.Kind
import com.uber.autodispose.AutoDispose
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider
import javax.inject.Inject
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector
import io.reactivex.android.schedulers.AndroidSchedulers
@ -39,6 +35,7 @@ import kotlinx.android.extensions.CacheImplementation
import kotlinx.android.extensions.ContainerOptions
import kotlinx.android.synthetic.main.toolbar_basic.*
import net.accelf.yuito.QuickTootHelper
import javax.inject.Inject
class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
@ -76,7 +73,7 @@ class StatusListActivity : BottomSheetActivity(), HasAndroidInjector {
val quickTootContainer = findViewById<ConstraintLayout>(R.id.quick_toot_container)
val composeButton = findViewById<FloatingActionButton>(R.id.floating_btn)
val quickTootHelper = QuickTootHelper(quickTootContainer, accountManager, eventHub)
val quickTootHelper = QuickTootHelper(this, quickTootContainer, accountManager, eventHub)
eventHub.events
.observeOn(AndroidSchedulers.mainThread())

View File

@ -81,7 +81,7 @@ public class ViewTagActivity extends BottomSheetActivity implements HasAndroidIn
fragmentTransaction.commit();
ConstraintLayout quickTootContainer = findViewById(R.id.quick_toot_container);
QuickTootHelper quickTootHelper = new QuickTootHelper(quickTootContainer, accountManager, eventHub);
QuickTootHelper quickTootHelper = new QuickTootHelper(this, quickTootContainer, accountManager, eventHub);
eventHub.getEvents()
.observeOn(AndroidSchedulers.mainThread())

View File

@ -0,0 +1,27 @@
package com.keylesspalace.tusky.entity
import android.text.Spanned
import com.google.gson.annotations.SerializedName
import java.util.*
data class Announcement(
val id: String,
val content: Spanned,
@SerializedName("starts_at") val startsAt: Date,
@SerializedName("ends_at") val endsAt: Date,
@SerializedName("all_day") val allDay: Boolean,
val emojis: List<Emoji>,
val mentions: Array<Status.Mention>
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || javaClass != other.javaClass) return false
val announcement = other as Announcement?
return id == announcement?.id
}
override fun hashCode(): Int {
return id.hashCode()
}
}

View File

@ -479,6 +479,9 @@ interface MastodonApi {
@Field("choices[]") choices: List<Int>
): Single<Poll>
@GET("api/v1/announcements")
fun listAnnouncements(): Single<List<Announcement>>
@POST("api/v1/accounts/{id}/block")
fun blockAccountObservable(
@Path("id") accountId: String

View File

@ -5,14 +5,21 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.lifecycle.Lifecycle;
import com.keylesspalace.tusky.AccountActivity;
import com.keylesspalace.tusky.BottomSheetActivity;
import com.keylesspalace.tusky.PostLookupFallbackBehavior;
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.ViewTagActivity;
import com.keylesspalace.tusky.appstore.DrawerFooterClickedEvent;
import com.keylesspalace.tusky.appstore.Event;
import com.keylesspalace.tusky.appstore.EventHub;
@ -21,16 +28,26 @@ import com.keylesspalace.tusky.appstore.QuickReplyEvent;
import com.keylesspalace.tusky.components.compose.ComposeActivity;
import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.entity.Announcement;
import com.keylesspalace.tusky.entity.Status;
import com.keylesspalace.tusky.interfaces.LinkListener;
import com.keylesspalace.tusky.util.LinkHelper;
import com.keylesspalace.tusky.util.ListUtils;
import com.keylesspalace.tusky.util.ThemeUtils;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import io.reactivex.android.schedulers.AndroidSchedulers;
import static com.keylesspalace.tusky.components.compose.ComposeActivity.CAN_USE_UNLEAKABLE;
import static com.keylesspalace.tusky.components.compose.ComposeActivity.PREF_DEFAULT_TAG;
import static com.keylesspalace.tusky.components.compose.ComposeActivity.PREF_USE_DEFAULT_TAG;
import static com.uber.autodispose.AutoDispose.autoDisposable;
import static com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from;
public class QuickTootHelper {
@ -39,22 +56,36 @@ public class QuickTootHelper {
private TextView defaultTagInfo;
private ImageView visibilityButton;
private EditText tootEditText;
private ImageButton openAnnouncementsButton;
private TextView announcementsText;
private ImageButton prevButton;
private ImageButton nextButton;
private TextView announcementsCountText;
private SharedPreferences defPrefs;
private String domain;
private String loggedInUsername;
private EventHub eventHub;
private LinkListener listener;
private Status inReplyTo;
private boolean open = false;
private int index = 0;
private List<Announcement> announcements;
private static final String PREF_CURRENT_VISIBILITY = "current_visibility";
public QuickTootHelper(ConstraintLayout root, AccountManager accountManager, EventHub eventHub) {
public QuickTootHelper(BottomSheetActivity activity, ConstraintLayout root, AccountManager accountManager, EventHub eventHub) {
context = root.getContext();
quickReplyInfo = root.findViewById(R.id.quick_reply_info);
defaultTagInfo = root.findViewById(R.id.default_tag_info);
visibilityButton = root.findViewById(R.id.visibility_button);
tootEditText = root.findViewById(R.id.toot_edit_text);
openAnnouncementsButton = root.findViewById(R.id.button_open_announcements);
announcementsText = root.findViewById(R.id.text_view_announcements);
prevButton = root.findViewById(R.id.button_prev_announcements);
nextButton = root.findViewById(R.id.button_next_announcements);
announcementsCountText = root.findViewById(R.id.text_view_announcements_count);
Button quickTootButton = root.findViewById(R.id.toot_button);
context = root.getContext();
@ -71,6 +102,37 @@ public class QuickTootHelper {
updateDefaultTagInfo();
visibilityButton.setOnClickListener(v -> setNextVisibility());
quickTootButton.setOnClickListener(v -> quickToot());
listener = new LinkListener() {
@Override
public void onViewTag(String tag) {
context.startActivity(ViewTagActivity.getIntent(context, tag));
}
@Override
public void onViewAccount(String id) {
context.startActivity(AccountActivity.getIntent(context, id));
}
@Override
public void onViewUrl(String url, String text) {
activity.viewUrl(url, text, PostLookupFallbackBehavior.OPEN_IN_BROWSER);
}
};
activity.mastodonApi.listAnnouncements()
.observeOn(AndroidSchedulers.mainThread())
.as(autoDisposable(from(activity, Lifecycle.Event.ON_DESTROY)))
.subscribe(
a -> {
announcements = a;
updateAnnouncements();
},
Throwable::printStackTrace
);
updateAnnouncements();
openAnnouncementsButton.setOnClickListener(v -> toggleOpenAnnouncements());
prevButton.setOnClickListener(v -> prevAnnouncement());
nextButton.setOnClickListener(v -> nextAnnouncement());
}
public void composeButton() {
@ -236,4 +298,50 @@ public class QuickTootHelper {
eventHub.dispatch(new PreferenceChangedEvent(PREF_CURRENT_VISIBILITY));
updateVisibilityButton();
}
private void updateAnnouncements() {
if (ListUtils.isEmpty(announcements)) {
openAnnouncementsButton.setVisibility(View.GONE);
announcementsText.setVisibility(View.GONE);
announcementsCountText.setVisibility(View.GONE);
prevButton.setVisibility(View.GONE);
nextButton.setVisibility(View.GONE);
} else {
openAnnouncementsButton.setVisibility(View.VISIBLE);
announcementsText.setVisibility(View.VISIBLE);
announcementsCountText.setVisibility(View.VISIBLE);
if (open) {
prevButton.setVisibility(View.VISIBLE);
nextButton.setVisibility(View.VISIBLE);
} else {
prevButton.setVisibility(View.GONE);
nextButton.setVisibility(View.GONE);
}
openAnnouncementsButton.setImageDrawable(context.getDrawable(open ? R.drawable.ic_arrow_drop_down : R.drawable.ic_arrow_drop_up));
announcementsText.setSingleLine(!open);
announcementsCountText.setText(String.format(Locale.getDefault(), "(%d/%d)", index + 1, announcements.size()));
Announcement announcement = announcements.get(index);
LinkHelper.setClickableText(announcementsText, announcement.getContent(), announcement.getMentions(), listener, false);
}
}
private void toggleOpenAnnouncements() {
open = !open;
updateAnnouncements();
}
private void prevAnnouncement() {
if (index > 0) {
index--;
updateAnnouncements();
}
}
private void nextAnnouncement() {
if (index < announcements.size() - 1) {
index++;
updateAnnouncements();
}
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M7,10l5,5 5,-5z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M7,14l5,-5 5,5z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
</vector>

View File

@ -5,6 +5,69 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="@+id/button_open_announcements"
style="?attr/image_button_style"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="12dp"
android:layout_marginTop="4dp"
android:padding="4dp"
android:contentDescription="@string/action_more"
android:importantForAccessibility="no"
app:layout_constraintBottom_toTopOf="@+id/quick_reply_info"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/ic_arrow_drop_up" />
<TextView
android:id="@+id/text_view_announcements"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toTopOf="@+id/quick_reply_info"
app:layout_constraintStart_toEndOf="@+id/button_open_announcements" />
<ImageButton
android:id="@+id/button_prev_announcements"
style="?attr/image_button_style"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="12dp"
android:layout_marginTop="4dp"
android:padding="4dp"
android:contentDescription="@string/action_more"
android:importantForAccessibility="no"
app:layout_constraintBottom_toTopOf="@+id/text_view_announcements_count"
app:layout_constraintEnd_toStartOf="@id/button_next_announcements"
app:srcCompat="@drawable/ic_chevron_left" />
<ImageButton
android:id="@+id/button_next_announcements"
style="?attr/image_button_style"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="12dp"
android:layout_marginTop="4dp"
android:padding="4dp"
android:contentDescription="@string/action_more"
android:importantForAccessibility="no"
app:layout_constraintBottom_toTopOf="@+id/text_view_announcements_count"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="@drawable/ic_chevron_right" />
<TextView
android:id="@+id/text_view_announcements_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toTopOf="@id/quick_reply_info"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/quick_reply_info"
android:layout_width="wrap_content"