Add basic lists support (#501)
This commit is contained in:
parent
dd9bba94bb
commit
6152043df3
13 changed files with 405 additions and 26 deletions
|
@ -95,6 +95,8 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
|
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".ListsActivity" />
|
||||||
|
<activity android:name=".ModalTimelineActivity" />
|
||||||
|
|
||||||
<receiver android:name=".receiver.NotificationClearBroadcastReceiver" />
|
<receiver android:name=".receiver.NotificationClearBroadcastReceiver" />
|
||||||
|
|
||||||
|
|
199
app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt
Normal file
199
app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
package com.keylesspalace.tusky
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v4.widget.TextViewCompat
|
||||||
|
import android.support.v7.widget.DividerItemDecoration
|
||||||
|
import android.support.v7.widget.LinearLayoutManager
|
||||||
|
import android.support.v7.widget.RecyclerView
|
||||||
|
import android.support.v7.widget.Toolbar
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.keylesspalace.tusky.entity.MastoList
|
||||||
|
import com.keylesspalace.tusky.fragment.TimelineFragment
|
||||||
|
import com.keylesspalace.tusky.network.MastodonApi
|
||||||
|
import com.keylesspalace.tusky.util.ThemeUtils
|
||||||
|
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||||
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
|
import com.varunest.sparkbutton.helpers.Utils
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.Response
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by charlag on 1/4/18.
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface ListsView {
|
||||||
|
fun update(state: State)
|
||||||
|
fun openTimeline(listId: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data class State(val lists: List<MastoList>, val isLoading: Boolean)
|
||||||
|
|
||||||
|
class ListsViewModel(private val api: MastodonApi) {
|
||||||
|
|
||||||
|
private var _view: WeakReference<ListsView>? = null
|
||||||
|
private val view: ListsView? get() = _view?.get()
|
||||||
|
private var state = State(listOf(), false)
|
||||||
|
|
||||||
|
fun attach(view: ListsView) {
|
||||||
|
this._view = WeakReference(view)
|
||||||
|
updateView()
|
||||||
|
loadIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun detach() {
|
||||||
|
this._view = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun didSelectItem(id: String) {
|
||||||
|
view?.openTimeline(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadIfNeeded() {
|
||||||
|
if (state.isLoading || !state.lists.isEmpty()) return
|
||||||
|
updateState(state.copy(isLoading = false))
|
||||||
|
|
||||||
|
api.getLists().enqueue(object : retrofit2.Callback<List<MastoList>> {
|
||||||
|
override fun onResponse(call: Call<List<MastoList>>, response: Response<List<MastoList>>) {
|
||||||
|
updateState(state.copy(lists = response.body() ?: listOf(), isLoading = false))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<List<MastoList>>, t: Throwable?) {
|
||||||
|
updateState(state.copy(isLoading = false))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateState(state: State) {
|
||||||
|
this.state = state
|
||||||
|
view?.update(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateView() {
|
||||||
|
view?.update(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListsActivity : BaseActivity(), ListsView {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun newIntent(context: Context): Intent {
|
||||||
|
return Intent(context, ListsActivity::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var recyclerView: RecyclerView
|
||||||
|
private lateinit var progressBar: ProgressBar
|
||||||
|
|
||||||
|
private lateinit var viewModel: ListsViewModel
|
||||||
|
private val adapter = ListsAdapter()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_lists)
|
||||||
|
|
||||||
|
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||||
|
recyclerView = findViewById(R.id.lists_recycler)
|
||||||
|
progressBar = findViewById(R.id.progress_bar)
|
||||||
|
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
val bar = supportActionBar
|
||||||
|
if (bar != null) {
|
||||||
|
bar.title = getString(R.string.title_lists)
|
||||||
|
bar.setDisplayHomeAsUpEnabled(true)
|
||||||
|
bar.setDisplayShowHomeEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
recyclerView.adapter = adapter
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||||
|
recyclerView.addItemDecoration(
|
||||||
|
DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
|
||||||
|
|
||||||
|
viewModel = lastNonConfigurationInstance as? ListsViewModel ?: ListsViewModel(mastodonApi)
|
||||||
|
viewModel.attach(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
viewModel.detach()
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRetainCustomNonConfigurationInstance(): Any {
|
||||||
|
return viewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun update(state: State) {
|
||||||
|
adapter.update(state.lists)
|
||||||
|
progressBar.visibility = if (state.isLoading) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openTimeline(listId: String) {
|
||||||
|
startActivity(
|
||||||
|
ModalTimelineActivity.newIntent(this, TimelineFragment.Kind.LIST, listId))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (item.itemId == android.R.id.home) {
|
||||||
|
onBackPressed()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class ListsAdapter : RecyclerView.Adapter<ListsAdapter.ListViewHolder>() {
|
||||||
|
|
||||||
|
private val items = mutableListOf<MastoList>()
|
||||||
|
|
||||||
|
fun update(list: List<MastoList>) {
|
||||||
|
this.items.clear()
|
||||||
|
this.items.addAll(list)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
|
||||||
|
return LayoutInflater.from(parent.context).inflate(R.layout.item_list, parent, false)
|
||||||
|
.let(this::ListViewHolder)
|
||||||
|
.apply {
|
||||||
|
val context = nameTextView.context
|
||||||
|
val icon = IconicsDrawable(context, GoogleMaterial.Icon.gmd_list)
|
||||||
|
val size = Utils.dpToPx(context, 20)
|
||||||
|
ThemeUtils.setDrawableTint(context, icon, android.R.attr.textColorTertiary)
|
||||||
|
icon.setBounds(0, 0, size, size)
|
||||||
|
nameTextView.compoundDrawablePadding = Utils.dpToPx(context, 8)
|
||||||
|
TextViewCompat.setCompoundDrawablesRelative(
|
||||||
|
nameTextView, icon, null, null, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
|
||||||
|
holder.nameTextView.text = items[position].title
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class ListViewHolder(view: View) : RecyclerView.ViewHolder(view),
|
||||||
|
View.OnClickListener {
|
||||||
|
val nameTextView: TextView = view.findViewById(R.id.list_name_textview)
|
||||||
|
|
||||||
|
init {
|
||||||
|
view.setOnClickListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View?) {
|
||||||
|
viewModel.didSelectItem(items[adapterPosition].id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,6 +77,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
|
||||||
private static final long DRAWER_ITEM_LOG_OUT = 7;
|
private static final long DRAWER_ITEM_LOG_OUT = 7;
|
||||||
private static final long DRAWER_ITEM_FOLLOW_REQUESTS = 8;
|
private static final long DRAWER_ITEM_FOLLOW_REQUESTS = 8;
|
||||||
private static final long DRAWER_ITEM_SAVED_TOOT = 9;
|
private static final long DRAWER_ITEM_SAVED_TOOT = 9;
|
||||||
|
private static final long DRAWER_ITEM_LISTS = 10;
|
||||||
|
|
||||||
private static int COMPOSE_RESULT = 1;
|
private static int COMPOSE_RESULT = 1;
|
||||||
|
|
||||||
|
@ -311,6 +312,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
|
||||||
List<IDrawerItem> listItem = new ArrayList<>();
|
List<IDrawerItem> listItem = new ArrayList<>();
|
||||||
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_EDIT_PROFILE).withName(getString(R.string.action_edit_profile)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_person));
|
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_EDIT_PROFILE).withName(getString(R.string.action_edit_profile)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_person));
|
||||||
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_FAVOURITES).withName(getString(R.string.action_view_favourites)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_star));
|
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_FAVOURITES).withName(getString(R.string.action_view_favourites)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_star));
|
||||||
|
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_LISTS).withName(R.string.action_lists).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_list));
|
||||||
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_MUTED_USERS).withName(getString(R.string.action_view_mutes)).withSelectable(false).withIcon(muteDrawable));
|
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_MUTED_USERS).withName(getString(R.string.action_view_mutes)).withSelectable(false).withIcon(muteDrawable));
|
||||||
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_BLOCKED_USERS).withName(getString(R.string.action_view_blocks)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_block));
|
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_BLOCKED_USERS).withName(getString(R.string.action_view_blocks)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_block));
|
||||||
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_SEARCH).withName(getString(R.string.action_search)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_search));
|
listItem.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_SEARCH).withName(getString(R.string.action_search)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_search));
|
||||||
|
@ -366,6 +368,8 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
|
||||||
} else if (drawerItemIdentifier == DRAWER_ITEM_SAVED_TOOT) {
|
} else if (drawerItemIdentifier == DRAWER_ITEM_SAVED_TOOT) {
|
||||||
Intent intent = new Intent(MainActivity.this, SavedTootActivity.class);
|
Intent intent = new Intent(MainActivity.this, SavedTootActivity.class);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
|
} else if (drawerItemIdentifier == DRAWER_ITEM_LISTS) {
|
||||||
|
startActivity(ListsActivity.newIntent(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.keylesspalace.tusky
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.design.widget.FloatingActionButton
|
||||||
|
import android.support.v7.widget.Toolbar
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import com.keylesspalace.tusky.fragment.TimelineFragment
|
||||||
|
import com.keylesspalace.tusky.interfaces.ActionButtonActivity
|
||||||
|
|
||||||
|
class ModalTimelineActivity : BaseActivity(), ActionButtonActivity {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val ARG_KIND = "kind"
|
||||||
|
private const val ARG_ARG = "arg"
|
||||||
|
@JvmStatic fun newIntent(context: Context, kind: TimelineFragment.Kind,
|
||||||
|
argument: String?): Intent {
|
||||||
|
val intent = Intent(context, ModalTimelineActivity::class.java)
|
||||||
|
intent.putExtra(ARG_KIND, kind)
|
||||||
|
intent.putExtra(ARG_ARG, argument)
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
lateinit var contentFrame: FrameLayout
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_modal_timeline)
|
||||||
|
contentFrame = findViewById(R.id.content_frame)
|
||||||
|
|
||||||
|
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
val bar = supportActionBar
|
||||||
|
if (bar != null) {
|
||||||
|
bar.title = getString(R.string.title_list_timeline)
|
||||||
|
bar.setDisplayHomeAsUpEnabled(true)
|
||||||
|
bar.setDisplayShowHomeEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportFragmentManager.findFragmentById(R.id.content_frame) == null) {
|
||||||
|
val kind = intent?.getSerializableExtra(ARG_KIND) as? TimelineFragment.Kind ?:
|
||||||
|
TimelineFragment.Kind.HOME
|
||||||
|
val argument = intent?.getStringExtra(ARG_ARG)
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.content_frame, TimelineFragment.newInstance(kind, argument))
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getActionButton(): FloatingActionButton? = null
|
||||||
|
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (item.itemId == android.R.id.home) {
|
||||||
|
onBackPressed()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.keylesspalace.tusky.entity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by charlag on 1/4/18.
|
||||||
|
*/
|
||||||
|
|
||||||
|
data class MastoList(val id: String, val title: String)
|
|
@ -80,7 +80,8 @@ public class TimelineFragment extends SFragment implements
|
||||||
PUBLIC_FEDERATED,
|
PUBLIC_FEDERATED,
|
||||||
TAG,
|
TAG,
|
||||||
USER,
|
USER,
|
||||||
FAVOURITES
|
FAVOURITES,
|
||||||
|
LIST
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum FetchEnd {
|
private enum FetchEnd {
|
||||||
|
@ -158,7 +159,7 @@ public class TimelineFragment extends SFragment implements
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
Bundle arguments = getArguments();
|
Bundle arguments = getArguments();
|
||||||
kind = Kind.valueOf(arguments.getString(KIND_ARG));
|
kind = Kind.valueOf(arguments.getString(KIND_ARG));
|
||||||
if (kind == Kind.TAG || kind == Kind.USER) {
|
if (kind == Kind.TAG || kind == Kind.USER || kind == Kind.LIST) {
|
||||||
hashtagOrId = arguments.getString(HASHTAG_OR_ID_ARG);
|
hashtagOrId = arguments.getString(HASHTAG_OR_ID_ARG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,19 +210,23 @@ public class TimelineFragment extends SFragment implements
|
||||||
|
|
||||||
if (jumpToTopAllowed()) {
|
if (jumpToTopAllowed()) {
|
||||||
TabLayout layout = getActivity().findViewById(R.id.tab_layout);
|
TabLayout layout = getActivity().findViewById(R.id.tab_layout);
|
||||||
onTabSelectedListener = new TabLayout.OnTabSelectedListener() {
|
if (layout != null) {
|
||||||
@Override
|
onTabSelectedListener = new TabLayout.OnTabSelectedListener() {
|
||||||
public void onTabSelected(TabLayout.Tab tab) {}
|
@Override
|
||||||
|
public void onTabSelected(TabLayout.Tab tab) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTabUnselected(TabLayout.Tab tab) {}
|
public void onTabUnselected(TabLayout.Tab tab) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTabReselected(TabLayout.Tab tab) {
|
public void onTabReselected(TabLayout.Tab tab) {
|
||||||
jumpToTop();
|
jumpToTop();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
layout.addOnTabSelectedListener(onTabSelectedListener);
|
layout.addOnTabSelectedListener(onTabSelectedListener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is delayed until onActivityCreated solely because MainActivity.composeButton isn't
|
/* This is delayed until onActivityCreated solely because MainActivity.composeButton isn't
|
||||||
|
@ -273,7 +278,9 @@ public class TimelineFragment extends SFragment implements
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
if (jumpToTopAllowed()) {
|
if (jumpToTopAllowed()) {
|
||||||
TabLayout tabLayout = getActivity().findViewById(R.id.tab_layout);
|
TabLayout tabLayout = getActivity().findViewById(R.id.tab_layout);
|
||||||
tabLayout.removeOnTabSelectedListener(onTabSelectedListener);
|
if (tabLayout != null) {
|
||||||
|
tabLayout.removeOnTabSelectedListener(onTabSelectedListener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(timelineReceiver);
|
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(timelineReceiver);
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
|
@ -532,6 +539,8 @@ public class TimelineFragment extends SFragment implements
|
||||||
return api.accountStatuses(tagOrId, fromId, uptoId, LOAD_AT_ONCE, null);
|
return api.accountStatuses(tagOrId, fromId, uptoId, LOAD_AT_ONCE, null);
|
||||||
case FAVOURITES:
|
case FAVOURITES:
|
||||||
return api.favourites(fromId, uptoId, LOAD_AT_ONCE);
|
return api.favourites(fromId, uptoId, LOAD_AT_ONCE);
|
||||||
|
case LIST:
|
||||||
|
return api.listTimeline(tagOrId, fromId, uptoId, LOAD_AT_ONCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import com.keylesspalace.tusky.entity.Account;
|
||||||
import com.keylesspalace.tusky.entity.AppCredentials;
|
import com.keylesspalace.tusky.entity.AppCredentials;
|
||||||
import com.keylesspalace.tusky.entity.Attachment;
|
import com.keylesspalace.tusky.entity.Attachment;
|
||||||
import com.keylesspalace.tusky.entity.Card;
|
import com.keylesspalace.tusky.entity.Card;
|
||||||
|
import com.keylesspalace.tusky.entity.MastoList;
|
||||||
import com.keylesspalace.tusky.entity.Notification;
|
import com.keylesspalace.tusky.entity.Notification;
|
||||||
import com.keylesspalace.tusky.entity.Profile;
|
import com.keylesspalace.tusky.entity.Profile;
|
||||||
import com.keylesspalace.tusky.entity.Relationship;
|
import com.keylesspalace.tusky.entity.Relationship;
|
||||||
|
@ -67,6 +68,12 @@ public interface MastodonApi {
|
||||||
@Query("max_id") String maxId,
|
@Query("max_id") String maxId,
|
||||||
@Query("since_id") String sinceId,
|
@Query("since_id") String sinceId,
|
||||||
@Query("limit") Integer limit);
|
@Query("limit") Integer limit);
|
||||||
|
@GET("api/v1/timelines/list/{listId}")
|
||||||
|
Call<List<Status>> listTimeline(
|
||||||
|
@Path("listId") String listId,
|
||||||
|
@Query("max_id") String maxId,
|
||||||
|
@Query("since_id") String sinceId,
|
||||||
|
@Query("limit") Integer limit);
|
||||||
|
|
||||||
@GET("api/v1/notifications")
|
@GET("api/v1/notifications")
|
||||||
Call<List<Notification>> notifications(
|
Call<List<Notification>> notifications(
|
||||||
|
@ -236,4 +243,7 @@ public interface MastodonApi {
|
||||||
Call<Card> statusCard(
|
Call<Card> statusCard(
|
||||||
@Path("id") String statusId
|
@Path("id") String statusId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@GET("/api/v1/lists")
|
||||||
|
Call<List<MastoList>> getLists();
|
||||||
}
|
}
|
||||||
|
|
37
app/src/main/res/layout/activity_lists.xml
Normal file
37
app/src/main/res/layout/activity_lists.xml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<include layout="@layout/toolbar_basic" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/toolbar_shadow_shim"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/appbar" />
|
||||||
|
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:id="@+id/lists_recycler"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/toolbar_shadow_shim" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</android.support.constraint.ConstraintLayout>
|
27
app/src/main/res/layout/activity_modal_timeline.xml
Normal file
27
app/src/main/res/layout/activity_modal_timeline.xml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context="com.keylesspalace.tusky.ModalTimelineActivity">
|
||||||
|
|
||||||
|
<include layout="@layout/toolbar_basic" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/toolbar_shadow_shim"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/appbar" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/content_frame"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/toolbar_shadow_shim"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
</android.support.constraint.ConstraintLayout>
|
21
app/src/main/res/layout/item_list.xml
Normal file
21
app/src/main/res/layout/item_list.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:clickable="true">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/list_name_textview"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:textSize="?attr/status_text_medium"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Example list" />
|
||||||
|
</android.support.constraint.ConstraintLayout>
|
|
@ -3,6 +3,7 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<android.support.design.widget.AppBarLayout
|
<android.support.design.widget.AppBarLayout
|
||||||
|
android:id="@+id/appbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:stateListAnimator="@null"
|
android:stateListAnimator="@null"
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
<View xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/toolbar_shadow_shim"
|
||||||
<View
|
android:layout_width="match_parent"
|
||||||
android:id="@+id/toolbar_shadow_shim"
|
android:layout_height="4dp"
|
||||||
android:layout_width="match_parent"
|
android:background="@drawable/material_drawer_shadow_bottom"
|
||||||
android:layout_height="4dp"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
android:background="@drawable/material_drawer_shadow_bottom"
|
app:layout_collapseMode="pin" />
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
|
||||||
app:layout_collapseMode="pin" />
|
|
||||||
|
|
||||||
</merge>
|
|
|
@ -272,6 +272,9 @@
|
||||||
<string name="title_media">Media</string>
|
<string name="title_media">Media</string>
|
||||||
<string name="replying_to">Replying to @%s</string>
|
<string name="replying_to">Replying to @%s</string>
|
||||||
<string name="load_more_placeholder_text">load more</string>
|
<string name="load_more_placeholder_text">load more</string>
|
||||||
|
<string name="action_lists">Lists</string>
|
||||||
|
<string name="title_lists">Lists</string>
|
||||||
|
<string name="title_list_timeline">List timeline</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue