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>
|
||||
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
|
||||
</activity>
|
||||
<activity android:name=".ListsActivity" />
|
||||
<activity android:name=".ModalTimelineActivity" />
|
||||
|
||||
<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_FOLLOW_REQUESTS = 8;
|
||||
private static final long DRAWER_ITEM_SAVED_TOOT = 9;
|
||||
private static final long DRAWER_ITEM_LISTS = 10;
|
||||
|
||||
private static int COMPOSE_RESULT = 1;
|
||||
|
||||
|
@ -311,6 +312,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
|
|||
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_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_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));
|
||||
|
@ -366,6 +368,8 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
|
|||
} else if (drawerItemIdentifier == DRAWER_ITEM_SAVED_TOOT) {
|
||||
Intent intent = new Intent(MainActivity.this, SavedTootActivity.class);
|
||||
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,
|
||||
TAG,
|
||||
USER,
|
||||
FAVOURITES
|
||||
FAVOURITES,
|
||||
LIST
|
||||
}
|
||||
|
||||
private enum FetchEnd {
|
||||
|
@ -158,7 +159,7 @@ public class TimelineFragment extends SFragment implements
|
|||
Bundle savedInstanceState) {
|
||||
Bundle arguments = getArguments();
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -209,12 +210,15 @@ public class TimelineFragment extends SFragment implements
|
|||
|
||||
if (jumpToTopAllowed()) {
|
||||
TabLayout layout = getActivity().findViewById(R.id.tab_layout);
|
||||
if (layout != null) {
|
||||
onTabSelectedListener = new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {}
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {}
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
|
@ -223,6 +227,7 @@ public class TimelineFragment extends SFragment implements
|
|||
};
|
||||
layout.addOnTabSelectedListener(onTabSelectedListener);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is delayed until onActivityCreated solely because MainActivity.composeButton isn't
|
||||
* guaranteed to be set until then. */
|
||||
|
@ -273,8 +278,10 @@ public class TimelineFragment extends SFragment implements
|
|||
public void onDestroyView() {
|
||||
if (jumpToTopAllowed()) {
|
||||
TabLayout tabLayout = getActivity().findViewById(R.id.tab_layout);
|
||||
if (tabLayout != null) {
|
||||
tabLayout.removeOnTabSelectedListener(onTabSelectedListener);
|
||||
}
|
||||
}
|
||||
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(timelineReceiver);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
@ -532,6 +539,8 @@ public class TimelineFragment extends SFragment implements
|
|||
return api.accountStatuses(tagOrId, fromId, uptoId, LOAD_AT_ONCE, null);
|
||||
case FAVOURITES:
|
||||
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.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Card;
|
||||
import com.keylesspalace.tusky.entity.MastoList;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.entity.Profile;
|
||||
import com.keylesspalace.tusky.entity.Relationship;
|
||||
|
@ -67,6 +68,12 @@ public interface MastodonApi {
|
|||
@Query("max_id") String maxId,
|
||||
@Query("since_id") String sinceId,
|
||||
@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")
|
||||
Call<List<Notification>> notifications(
|
||||
|
@ -236,4 +243,7 @@ public interface MastodonApi {
|
|||
Call<Card> statusCard(
|
||||
@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">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:stateListAnimator="@null"
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<View
|
||||
<View xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/toolbar_shadow_shim"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="4dp"
|
||||
android:background="@drawable/material_drawer_shadow_bottom"
|
||||
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="replying_to">Replying to @%s</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>
|
||||
|
|
Loading…
Reference in a new issue