mirror of
https://github.com/etesync/android
synced 2025-02-21 20:12:04 +00:00
ViewCollection: add a basic etebase collection viewing activity.
This commit is contained in:
parent
481dcc1944
commit
63a8bf91a9
@ -233,6 +233,10 @@
|
||||
android:exported="false"
|
||||
android:parentActivityName=".ui.AccountsActivity">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.etebase.CollectionActivity"
|
||||
android:exported="false"
|
||||
/>
|
||||
<activity
|
||||
android:name=".ui.ViewCollectionActivity"
|
||||
android:exported="false"
|
||||
|
@ -109,7 +109,7 @@ class EtebaseLocalCache private constructor(context: Context, username: String)
|
||||
val content = itemFile.readBytes()
|
||||
itemMgr.cacheLoad(content)
|
||||
}.filter { withDeleted || !it.isDeleted }.map {
|
||||
CachedItem(it, it.meta)
|
||||
CachedItem(it, it.meta, it.contentString)
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ class EtebaseLocalCache private constructor(context: Context, username: String)
|
||||
}
|
||||
val content = itemFile.readBytes()
|
||||
return itemMgr.cacheLoad(content).let {
|
||||
CachedItem(it, it.meta)
|
||||
CachedItem(it, it.meta, it.contentString)
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,4 +162,4 @@ class EtebaseLocalCache private constructor(context: Context, username: String)
|
||||
|
||||
data class CachedCollection(val col: Collection, val meta: CollectionMetadata)
|
||||
|
||||
data class CachedItem(val item: Item, val meta: ItemMetadata)
|
||||
data class CachedItem(val item: Item, val meta: ItemMetadata, val content: String)
|
@ -43,6 +43,7 @@ import com.etesync.syncadapter.model.ServiceEntity
|
||||
import com.etesync.syncadapter.resource.LocalAddressBook
|
||||
import com.etesync.syncadapter.resource.LocalCalendar
|
||||
import com.etesync.syncadapter.syncadapter.requestSync
|
||||
import com.etesync.syncadapter.ui.etebase.CollectionActivity
|
||||
import com.etesync.syncadapter.ui.setup.SetupUserInfoFragment
|
||||
import com.etesync.syncadapter.utils.HintManager
|
||||
import com.etesync.syncadapter.utils.ShowcaseBuilder
|
||||
@ -71,7 +72,11 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
|
||||
val adapter = list.adapter as ArrayAdapter<*>
|
||||
val info = adapter.getItem(position) as CollectionListItemInfo
|
||||
|
||||
startActivity(ViewCollectionActivity.newIntent(this@AccountActivity, account, info.legacyInfo!!))
|
||||
if (settings.isLegacy) {
|
||||
startActivity(ViewCollectionActivity.newIntent(this@AccountActivity, account, info.legacyInfo!!))
|
||||
} else {
|
||||
startActivity(CollectionActivity.newIntent(this@AccountActivity, account, info.uid))
|
||||
}
|
||||
}
|
||||
|
||||
private val formattedFingerprint: String?
|
||||
|
@ -0,0 +1,103 @@
|
||||
package com.etesync.syncadapter.ui.etebase
|
||||
|
||||
import android.accounts.Account
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.viewModels
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.observe
|
||||
import com.etebase.client.CollectionManager
|
||||
import com.etesync.syncadapter.*
|
||||
import com.etesync.syncadapter.ui.BaseActivity
|
||||
import org.jetbrains.anko.doAsync
|
||||
import org.jetbrains.anko.uiThread
|
||||
|
||||
class CollectionActivity() : BaseActivity() {
|
||||
private lateinit var account: Account
|
||||
private lateinit var colUid: String
|
||||
private val model: AccountCollectionViewModel by viewModels()
|
||||
private val itemsModel: ItemsViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
account = intent.extras!!.getParcelable(EXTRA_ACCOUNT)!!
|
||||
colUid = intent.extras!!.getString(EXTRA_COLLECTION_UID)!!
|
||||
|
||||
setContentView(R.layout.etebase_collection_activity)
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
model.loadCollection(this, account, colUid)
|
||||
model.observe(this) {
|
||||
itemsModel.loadItems(it)
|
||||
}
|
||||
supportFragmentManager.beginTransaction()
|
||||
.add(R.id.fragment_container, ViewCollectionFragment())
|
||||
.commit()
|
||||
}
|
||||
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val EXTRA_ACCOUNT = "account"
|
||||
private val EXTRA_COLLECTION_UID = "collectionUid"
|
||||
|
||||
fun newIntent(context: Context, account: Account, colUid: String): Intent {
|
||||
val intent = Intent(context, CollectionActivity::class.java)
|
||||
intent.putExtra(EXTRA_ACCOUNT, account)
|
||||
intent.putExtra(EXTRA_COLLECTION_UID, colUid)
|
||||
return intent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AccountCollectionViewModel : ViewModel() {
|
||||
private val collection = MutableLiveData<AccountCollectionHolder>()
|
||||
|
||||
fun loadCollection(context: Context, account: Account, colUid: String) {
|
||||
doAsync {
|
||||
val settings = AccountSettings(context, account)
|
||||
val etebaseLocalCache = EtebaseLocalCache.getInstance(context, account.name)
|
||||
val etebase = EtebaseLocalCache.getEtebase(context, HttpClient.sharedClient, settings)
|
||||
val colMgr = etebase.collectionManager
|
||||
val cachedCollection = synchronized(etebaseLocalCache) {
|
||||
etebaseLocalCache.collectionGet(colMgr, colUid)!!
|
||||
}
|
||||
uiThread {
|
||||
collection.value = AccountCollectionHolder(
|
||||
etebaseLocalCache,
|
||||
etebase,
|
||||
colMgr,
|
||||
cachedCollection
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun observe(owner: LifecycleOwner, observer: (AccountCollectionHolder) -> Unit) =
|
||||
collection.observe(owner, observer)
|
||||
}
|
||||
|
||||
data class AccountCollectionHolder(val etebaseLocalCache: EtebaseLocalCache, val etebase: com.etebase.client.Account, val colMgr: CollectionManager, val cachedCollection: CachedCollection)
|
||||
|
||||
class ItemsViewModel : ViewModel() {
|
||||
private val cachedItems = MutableLiveData<List<CachedItem>>()
|
||||
|
||||
fun loadItems(accountCollectionHolder: AccountCollectionHolder) {
|
||||
doAsync {
|
||||
val col = accountCollectionHolder.cachedCollection.col
|
||||
val itemMgr = accountCollectionHolder.colMgr.getItemManager(col)
|
||||
val items = accountCollectionHolder.etebaseLocalCache.itemList(itemMgr, col.uid, withDeleted = true)
|
||||
uiThread {
|
||||
cachedItems.value = items
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun observe(owner: LifecycleOwner, observer: (List<CachedItem>) -> Unit) =
|
||||
cachedItems.observe(owner, observer)
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
package com.etesync.syncadapter.ui.etebase
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import androidx.fragment.app.ListFragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import com.etesync.syncadapter.CachedCollection
|
||||
import com.etesync.syncadapter.CachedItem
|
||||
import com.etesync.syncadapter.Constants
|
||||
import com.etesync.syncadapter.R
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.concurrent.Future
|
||||
|
||||
class ListEntriesFragment : ListFragment(), AdapterView.OnItemClickListener {
|
||||
private val model: AccountCollectionViewModel by activityViewModels()
|
||||
private val itemsModel: ItemsViewModel by activityViewModels()
|
||||
private var asyncTask: Future<Unit>? = null
|
||||
|
||||
private var emptyTextView: TextView? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val view = inflater.inflate(R.layout.journal_viewer_list, container, false)
|
||||
|
||||
//This is instead of setEmptyText() function because of Google bug
|
||||
//See: https://code.google.com/p/android/issues/detail?id=21742
|
||||
emptyTextView = view.findViewById<View>(android.R.id.empty) as TextView
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
model.observe(this) { col ->
|
||||
itemsModel.observe(this) {
|
||||
val entries = it.sortedByDescending { item ->
|
||||
item.meta.mtime ?: 0
|
||||
}
|
||||
val listAdapter = EntriesListAdapter(requireContext(), col.cachedCollection)
|
||||
setListAdapter(listAdapter)
|
||||
|
||||
listAdapter.addAll(entries)
|
||||
|
||||
emptyTextView!!.text = getString(R.string.journal_entries_list_empty)
|
||||
}
|
||||
}
|
||||
|
||||
listView.onItemClickListener = this
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
if (asyncTask != null)
|
||||
asyncTask!!.cancel(true)
|
||||
}
|
||||
|
||||
override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||
val item = listAdapter?.getItem(position) as CachedItem
|
||||
Toast.makeText(context, "Clicked ${item.item.uid}", Toast.LENGTH_LONG).show()
|
||||
// startActivity(JournalItemActivity.newIntent(requireContext(), account, info, entry.content))
|
||||
}
|
||||
|
||||
internal inner class EntriesListAdapter(context: Context, val cachedCollection: CachedCollection) : ArrayAdapter<CachedItem>(context, R.layout.journal_viewer_list_item) {
|
||||
|
||||
override fun getView(position: Int, _v: View?, parent: ViewGroup): View {
|
||||
var v = _v
|
||||
if (v == null)
|
||||
v = LayoutInflater.from(context).inflate(R.layout.journal_viewer_list_item, parent, false)!!
|
||||
|
||||
val item = getItem(position)
|
||||
|
||||
setItemView(v, cachedCollection.meta.collectionType, item)
|
||||
|
||||
/* FIXME: handle entry error:
|
||||
val entryError = data.select(EntryErrorEntity::class.java).where(EntryErrorEntity.ENTRY.eq(entryEntity)).limit(1).get().firstOrNull()
|
||||
if (entryError != null) {
|
||||
val errorIcon = v.findViewById<View>(R.id.error) as ImageView
|
||||
errorIcon.visibility = View.VISIBLE
|
||||
}
|
||||
*/
|
||||
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val dateFormatter = SimpleDateFormat()
|
||||
private fun getLine(content: String?, prefix: String): String? {
|
||||
var content: String? = content ?: return null
|
||||
|
||||
val start = content!!.indexOf(prefix)
|
||||
if (start >= 0) {
|
||||
val end = content.indexOf("\n", start)
|
||||
content = content.substring(start + prefix.length, end)
|
||||
} else {
|
||||
content = null
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
fun setItemView(v: View, collectionType: String, item: CachedItem) {
|
||||
|
||||
var tv = v.findViewById<View>(R.id.title) as TextView
|
||||
|
||||
// FIXME: hacky way to make it show sensible info
|
||||
val prefix: String = when (collectionType) {
|
||||
Constants.ETEBASE_TYPE_CALENDAR, Constants.ETEBASE_TYPE_TASKS -> {
|
||||
"SUMMARY:"
|
||||
}
|
||||
Constants.ETEBASE_TYPE_ADDRESS_BOOK -> {
|
||||
"FN:"
|
||||
}
|
||||
else -> {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
val fullContent = item.content
|
||||
var content = getLine(fullContent, prefix)
|
||||
content = content ?: "Not found"
|
||||
tv.text = content
|
||||
|
||||
tv = v.findViewById<View>(R.id.description) as TextView
|
||||
// FIXME: Don't use a hard-coded string
|
||||
content = "Modified: ${dateFormatter.format(item.meta.mtime ?: 0)}"
|
||||
tv.text = content
|
||||
|
||||
val action = v.findViewById<View>(R.id.action) as ImageView
|
||||
if (item.item.isDeleted) {
|
||||
action.setImageResource(R.drawable.action_delete)
|
||||
} else {
|
||||
action.setImageResource(R.drawable.action_change)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package com.etesync.syncadapter.ui.etebase
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Color.parseColor
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import com.etesync.syncadapter.Constants
|
||||
import com.etesync.syncadapter.R
|
||||
import com.etesync.syncadapter.resource.LocalCalendar
|
||||
import com.etesync.syncadapter.ui.BaseActivity
|
||||
import com.etesync.syncadapter.ui.WebViewActivity
|
||||
import com.etesync.syncadapter.utils.HintManager
|
||||
import com.etesync.syncadapter.utils.ShowcaseBuilder
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import tourguide.tourguide.ToolTip
|
||||
import java.util.*
|
||||
|
||||
class ViewCollectionFragment : Fragment() {
|
||||
private val model: AccountCollectionViewModel by activityViewModels()
|
||||
private val itemsModel: ItemsViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val ret = super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
inflater.inflate(R.layout.view_collection_fragment, container)
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
model.observe(this) {
|
||||
if (container != null) {
|
||||
initUi(inflater, container, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
|
||||
model.observe(this) {
|
||||
(activity as? BaseActivity?)?.supportActionBar?.title = it.cachedCollection.meta.name
|
||||
}
|
||||
}
|
||||
|
||||
private fun initUi(inflater: LayoutInflater, container: ViewGroup, collectionHolder: AccountCollectionHolder) {
|
||||
val title = container.findViewById<TextView>(R.id.display_name)
|
||||
if (!HintManager.getHintSeen(requireContext(), HINT_IMPORT)) {
|
||||
val tourGuide = ShowcaseBuilder.getBuilder(requireActivity())
|
||||
.setToolTip(ToolTip().setTitle(getString(R.string.tourguide_title)).setDescription(getString(R.string.account_showcase_import)).setGravity(Gravity.BOTTOM))
|
||||
.setPointer(null)
|
||||
tourGuide.mOverlay.setHoleRadius(0)
|
||||
tourGuide.playOn(title)
|
||||
HintManager.setHintSeen(requireContext(), HINT_IMPORT, true)
|
||||
}
|
||||
|
||||
val fab = container.findViewById<FloatingActionButton>(R.id.fab)
|
||||
fab?.setOnClickListener {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setIcon(R.drawable.ic_info_dark)
|
||||
.setTitle(R.string.use_native_apps_title)
|
||||
.setMessage(R.string.use_native_apps_body)
|
||||
.setNegativeButton(R.string.navigation_drawer_guide, { _: DialogInterface, _: Int -> WebViewActivity.openUrl(requireContext(), Constants.helpUri) })
|
||||
.setPositiveButton(android.R.string.yes) { _, _ -> }.show()
|
||||
}
|
||||
|
||||
val col = collectionHolder.cachedCollection.col
|
||||
val meta = collectionHolder.cachedCollection.meta
|
||||
val isAdmin = col.accessLevel == "adm"
|
||||
|
||||
val colorSquare = container.findViewById<View>(R.id.color)
|
||||
val color = if (!meta.color.isNullOrBlank()) parseColor(meta.color) else LocalCalendar.defaultColor
|
||||
when (meta.collectionType) {
|
||||
Constants.ETEBASE_TYPE_CALENDAR -> {
|
||||
colorSquare.setBackgroundColor(color)
|
||||
}
|
||||
Constants.ETEBASE_TYPE_TASKS -> {
|
||||
colorSquare.setBackgroundColor(color)
|
||||
val tasksNotShowing = container.findViewById<View>(R.id.tasks_not_showing)
|
||||
tasksNotShowing.visibility = View.VISIBLE
|
||||
}
|
||||
Constants.ETEBASE_TYPE_ADDRESS_BOOK -> {
|
||||
colorSquare.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
title.text = meta.name
|
||||
|
||||
val desc = container.findViewById<TextView>(R.id.description)
|
||||
desc.text = meta.description
|
||||
|
||||
val owner = container.findViewById<TextView>(R.id.owner)
|
||||
if (isAdmin) {
|
||||
owner.visibility = View.GONE
|
||||
} else {
|
||||
owner.visibility = View.VISIBLE
|
||||
owner.text = "Shared with us" // FIXME: Figure out how to represent it and don't use a hardcoded string
|
||||
}
|
||||
|
||||
itemsModel.observe(this) {
|
||||
val stats = container.findViewById<TextView>(R.id.stats)
|
||||
container.findViewById<View>(R.id.progressBar).visibility = View.GONE
|
||||
stats.text = String.format(Locale.getDefault(), "Change log items: %d", it.size)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.fragment_view_collection, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.on_edit -> {
|
||||
Toast.makeText(context, "Edit", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
R.id.on_manage_members -> {
|
||||
Toast.makeText(context, "Manage", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
R.id.on_import -> {
|
||||
Toast.makeText(context, "Import", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val HINT_IMPORT = "Import"
|
||||
}
|
||||
}
|
11
app/src/main/res/layout/etebase_collection_activity.xml
Normal file
11
app/src/main/res/layout/etebase_collection_activity.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
68
app/src/main/res/layout/view_collection_fragment.xml
Normal file
68
app/src/main/res/layout/view_collection_fragment.xml
Normal file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
layout="@layout/collection_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/activity_margin" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="@dimen/activity_margin"
|
||||
android:text="@string/change_journal_title"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tasks_not_showing"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="@dimen/activity_margin"
|
||||
android:visibility="gone"
|
||||
android:text="@string/tasks_not_showing" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/activity_margin">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stats"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Stats:" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="right" />
|
||||
</LinearLayout>
|
||||
|
||||
<fragment android:name="com.etesync.syncadapter.ui.etebase.ListEntriesFragment"
|
||||
android:id="@+id/list_entries_container"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
android:src="@drawable/ic_add_light" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
27
app/src/main/res/menu/fragment_view_collection.xml
Normal file
27
app/src/main/res/menu/fragment_view_collection.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||
~ All rights reserved. This program and the accompanying materials
|
||||
~ are made available under the terms of the GNU Public License v3.0
|
||||
~ which accompanies this distribution, and is available at
|
||||
~ http://www.gnu.org/licenses/gpl.html
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item android:title="@string/view_collection_edit"
|
||||
android:id="@+id/on_edit"
|
||||
android:icon="@drawable/ic_edit_dark"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item android:title="@string/view_collection_members"
|
||||
android:id="@+id/on_manage_members"
|
||||
android:icon="@drawable/ic_members_dark"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item android:title="@string/view_collection_import"
|
||||
android:id="@+id/on_import"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
</menu>
|
Loading…
Reference in New Issue
Block a user