mirror of
https://github.com/etesync/android
synced 2025-02-22 12:32:03 +00:00
Implement showing changelog item.
This commit is contained in:
parent
71e37fb9a6
commit
cea7f8fdc6
@ -0,0 +1,436 @@
|
|||||||
|
package com.etesync.syncadapter.ui.etebase
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.format.DateFormat
|
||||||
|
import android.text.format.DateUtils
|
||||||
|
import android.view.*
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.fragment.app.FragmentPagerAdapter
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import at.bitfire.ical4android.Event
|
||||||
|
import at.bitfire.ical4android.InvalidCalendarException
|
||||||
|
import at.bitfire.ical4android.Task
|
||||||
|
import at.bitfire.vcard4android.Contact
|
||||||
|
import com.etesync.syncadapter.CachedCollection
|
||||||
|
import com.etesync.syncadapter.CachedItem
|
||||||
|
import com.etesync.syncadapter.Constants
|
||||||
|
import com.etesync.syncadapter.R
|
||||||
|
import com.etesync.syncadapter.ui.BaseActivity
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
|
import ezvcard.util.PartialDate
|
||||||
|
import org.jetbrains.anko.doAsync
|
||||||
|
import org.jetbrains.anko.uiThread
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.StringReader
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.Future
|
||||||
|
|
||||||
|
class CollectionItemFragment(private val cachedItem: CachedItem) : Fragment() {
|
||||||
|
private val collectionModel: CollectionViewModel by activityViewModels()
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
val ret = inflater.inflate(R.layout.journal_item_activity, container, false)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
collectionModel.observe(this) {
|
||||||
|
(activity as? BaseActivity?)?.supportActionBar?.title = it.meta.name
|
||||||
|
if (container != null) {
|
||||||
|
initUi(inflater, ret, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initUi(inflater: LayoutInflater, v: View, cachedCollection: CachedCollection) {
|
||||||
|
val viewPager = v.findViewById<ViewPager>(R.id.viewpager)
|
||||||
|
viewPager.adapter = TabsAdapter(childFragmentManager, requireContext(), cachedCollection, cachedItem)
|
||||||
|
|
||||||
|
val tabLayout = v.findViewById<TabLayout>(R.id.tabs)
|
||||||
|
tabLayout.setupWithViewPager(viewPager)
|
||||||
|
|
||||||
|
ListEntriesFragment.setItemView(v.findViewById(R.id.journal_list_item), cachedCollection.meta.collectionType, cachedItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
inflater.inflate(R.menu.collection_item_fragment, menu)
|
||||||
|
// menu.setGroupVisible(R.id.journal_item_menu_event_invite, emailInvitationEvent != null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TabsAdapter(fm: FragmentManager, private val context: Context, private val cachedCollection: CachedCollection, private val cachedItem: CachedItem) : FragmentPagerAdapter(fm) {
|
||||||
|
|
||||||
|
override fun getCount(): Int {
|
||||||
|
// FIXME: Make it depend on info enumType (only have non-raw for known types)
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPageTitle(position: Int): CharSequence? {
|
||||||
|
return if (position == 0) {
|
||||||
|
context.getString(R.string.journal_item_tab_main)
|
||||||
|
} else {
|
||||||
|
context.getString(R.string.journal_item_tab_raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItem(position: Int): Fragment {
|
||||||
|
return if (position == 0) {
|
||||||
|
PrettyFragment(cachedCollection, cachedItem.content)
|
||||||
|
} else {
|
||||||
|
TextFragment(cachedItem.content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TextFragment(private val content: String) : Fragment() {
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
val v = inflater.inflate(R.layout.text_fragment, container, false)
|
||||||
|
|
||||||
|
val tv = v.findViewById<View>(R.id.content) as TextView
|
||||||
|
|
||||||
|
tv.text = content
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrettyFragment(private val cachedCollection: CachedCollection, private val content: String) : Fragment() {
|
||||||
|
private var asyncTask: Future<Unit>? = null
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
var v: View? = null
|
||||||
|
|
||||||
|
when (cachedCollection.meta.collectionType) {
|
||||||
|
Constants.ETEBASE_TYPE_ADDRESS_BOOK -> {
|
||||||
|
v = inflater.inflate(R.layout.contact_info, container, false)
|
||||||
|
asyncTask = loadContactTask(v)
|
||||||
|
}
|
||||||
|
Constants.ETEBASE_TYPE_CALENDAR -> {
|
||||||
|
v = inflater.inflate(R.layout.event_info, container, false)
|
||||||
|
asyncTask = loadEventTask(v)
|
||||||
|
}
|
||||||
|
Constants.ETEBASE_TYPE_TASKS -> {
|
||||||
|
v = inflater.inflate(R.layout.task_info, container, false)
|
||||||
|
asyncTask = loadTaskTask(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
if (asyncTask != null)
|
||||||
|
asyncTask!!.cancel(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadEventTask(view: View): Future<Unit> {
|
||||||
|
return doAsync {
|
||||||
|
var event: Event? = null
|
||||||
|
val inputReader = StringReader(content)
|
||||||
|
|
||||||
|
try {
|
||||||
|
event = Event.eventsFromReader(inputReader, null)[0]
|
||||||
|
} catch (e: InvalidCalendarException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event != null) {
|
||||||
|
uiThread {
|
||||||
|
val loader = view.findViewById<View>(R.id.event_info_loading_msg)
|
||||||
|
loader.visibility = View.GONE
|
||||||
|
val contentContainer = view.findViewById<View>(R.id.event_info_scroll_view)
|
||||||
|
contentContainer.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
setTextViewText(view, R.id.title, event.summary)
|
||||||
|
|
||||||
|
setTextViewText(view, R.id.when_datetime, getDisplayedDatetime(event.dtStart?.date?.time!!, event.dtEnd?.date!!.time, event.isAllDay(), context))
|
||||||
|
|
||||||
|
setTextViewText(view, R.id.where, event.location)
|
||||||
|
|
||||||
|
val organizer = event.organizer
|
||||||
|
if (organizer != null) {
|
||||||
|
val tv = view.findViewById<View>(R.id.organizer) as TextView
|
||||||
|
tv.text = organizer.calAddress.toString().replaceFirst("mailto:".toRegex(), "")
|
||||||
|
} else {
|
||||||
|
val organizerView = view.findViewById<View>(R.id.organizer_container)
|
||||||
|
organizerView.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
setTextViewText(view, R.id.description, event.description)
|
||||||
|
|
||||||
|
var first = true
|
||||||
|
var sb = StringBuilder()
|
||||||
|
for (attendee in event.attendees) {
|
||||||
|
if (first) {
|
||||||
|
first = false
|
||||||
|
sb.append(getString(R.string.journal_item_attendees)).append(": ")
|
||||||
|
} else {
|
||||||
|
sb.append(", ")
|
||||||
|
}
|
||||||
|
sb.append(attendee.calAddress.toString().replaceFirst("mailto:".toRegex(), ""))
|
||||||
|
}
|
||||||
|
setTextViewText(view, R.id.attendees, sb.toString())
|
||||||
|
|
||||||
|
first = true
|
||||||
|
sb = StringBuilder()
|
||||||
|
for (alarm in event.alarms) {
|
||||||
|
if (first) {
|
||||||
|
first = false
|
||||||
|
sb.append(getString(R.string.journal_item_reminders)).append(": ")
|
||||||
|
} else {
|
||||||
|
sb.append(", ")
|
||||||
|
}
|
||||||
|
sb.append(alarm.trigger.value)
|
||||||
|
}
|
||||||
|
setTextViewText(view, R.id.reminders, sb.toString())
|
||||||
|
|
||||||
|
/* FIXME:
|
||||||
|
if (event.attendees.isNotEmpty() && activity != null) {
|
||||||
|
(activity as JournalItemActivity).allowSendEmail(event, syncEntry.content)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadTaskTask(view: View): Future<Unit> {
|
||||||
|
return doAsync {
|
||||||
|
var task: Task? = null
|
||||||
|
val inputReader = StringReader(content)
|
||||||
|
|
||||||
|
try {
|
||||||
|
task = Task.tasksFromReader(inputReader)[0]
|
||||||
|
} catch (e: InvalidCalendarException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task != null) {
|
||||||
|
uiThread {
|
||||||
|
val loader = view.findViewById<View>(R.id.task_info_loading_msg)
|
||||||
|
loader.visibility = View.GONE
|
||||||
|
val contentContainer = view.findViewById<View>(R.id.task_info_scroll_view)
|
||||||
|
contentContainer.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
setTextViewText(view, R.id.title, task.summary)
|
||||||
|
|
||||||
|
setTextViewText(view, R.id.where, task.location)
|
||||||
|
|
||||||
|
val organizer = task.organizer
|
||||||
|
if (organizer != null) {
|
||||||
|
val tv = view.findViewById<View>(R.id.organizer) as TextView
|
||||||
|
tv.text = organizer.calAddress.toString().replaceFirst("mailto:".toRegex(), "")
|
||||||
|
} else {
|
||||||
|
val organizerView = view.findViewById<View>(R.id.organizer_container)
|
||||||
|
organizerView.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
setTextViewText(view, R.id.description, task.description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadContactTask(view: View): Future<Unit> {
|
||||||
|
return doAsync {
|
||||||
|
var contact: Contact? = null
|
||||||
|
val reader = StringReader(content)
|
||||||
|
|
||||||
|
try {
|
||||||
|
contact = Contact.fromReader(reader, null)[0]
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contact != null) {
|
||||||
|
uiThread {
|
||||||
|
val loader = view.findViewById<View>(R.id.loading_msg)
|
||||||
|
loader.visibility = View.GONE
|
||||||
|
val contentContainer = view.findViewById<View>(R.id.content_container)
|
||||||
|
contentContainer.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
val tv = view.findViewById<View>(R.id.display_name) as TextView
|
||||||
|
tv.text = contact.displayName
|
||||||
|
|
||||||
|
if (contact.group) {
|
||||||
|
showGroup(contact)
|
||||||
|
} else {
|
||||||
|
showContact(contact)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun showGroup(contact: Contact) {
|
||||||
|
val view = requireView()
|
||||||
|
|
||||||
|
val mainCard = view.findViewById<View>(R.id.main_card) as ViewGroup
|
||||||
|
|
||||||
|
addInfoItem(view.context, mainCard, getString(R.string.journal_item_member_count), null, contact.members.size.toString())
|
||||||
|
|
||||||
|
for (member in contact.members) {
|
||||||
|
addInfoItem(view.context, mainCard, getString(R.string.journal_item_member), null, member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun showContact(contact: Contact) {
|
||||||
|
val view = requireView()
|
||||||
|
val mainCard = view.findViewById<View>(R.id.main_card) as ViewGroup
|
||||||
|
val aboutCard = view.findViewById<View>(R.id.about_card) as ViewGroup
|
||||||
|
aboutCard.findViewById<View>(R.id.title_container).visibility = View.VISIBLE
|
||||||
|
|
||||||
|
// TEL
|
||||||
|
for (labeledPhone in contact.phoneNumbers) {
|
||||||
|
val types = labeledPhone.property.types
|
||||||
|
val type = if (types.size > 0) types[0].value else null
|
||||||
|
addInfoItem(view.context, mainCard, getString(R.string.journal_item_phone), type, labeledPhone.property.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EMAIL
|
||||||
|
for (labeledEmail in contact.emails) {
|
||||||
|
val types = labeledEmail.property.types
|
||||||
|
val type = if (types.size > 0) types[0].value else null
|
||||||
|
addInfoItem(view.context, mainCard, getString(R.string.journal_item_email), type, labeledEmail.property.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ORG, TITLE, ROLE
|
||||||
|
if (contact.organization != null) {
|
||||||
|
addInfoItem(view.context, aboutCard, getString(R.string.journal_item_organization), contact.jobTitle, contact.organization?.values!![0])
|
||||||
|
}
|
||||||
|
if (contact.jobDescription != null) {
|
||||||
|
addInfoItem(view.context, aboutCard, getString(R.string.journal_item_job_description), null, contact.jobTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IMPP
|
||||||
|
for (labeledImpp in contact.impps) {
|
||||||
|
addInfoItem(view.context, mainCard, getString(R.string.journal_item_impp), labeledImpp.property.protocol, labeledImpp.property.handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NICKNAME
|
||||||
|
if (contact.nickName != null && !contact.nickName?.values?.isEmpty()!!) {
|
||||||
|
addInfoItem(view.context, aboutCard, getString(R.string.journal_item_nickname), null, contact.nickName?.values!![0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADR
|
||||||
|
for (labeledAddress in contact.addresses) {
|
||||||
|
val types = labeledAddress.property.types
|
||||||
|
val type = if (types.size > 0) types[0].value else null
|
||||||
|
addInfoItem(view.context, mainCard, getString(R.string.journal_item_address), type, labeledAddress.property.label)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE
|
||||||
|
if (contact.note != null) {
|
||||||
|
addInfoItem(view.context, aboutCard, getString(R.string.journal_item_note), null, contact.note)
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL
|
||||||
|
for (labeledUrl in contact.urls) {
|
||||||
|
addInfoItem(view.context, aboutCard, getString(R.string.journal_item_website), null, labeledUrl.property.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ANNIVERSARY
|
||||||
|
if (contact.anniversary != null) {
|
||||||
|
addInfoItem(view.context, aboutCard, getString(R.string.journal_item_anniversary), null, getDisplayedDate(contact.anniversary?.date, contact.anniversary?.partialDate))
|
||||||
|
}
|
||||||
|
// BDAY
|
||||||
|
if (contact.birthDay != null) {
|
||||||
|
addInfoItem(view.context, aboutCard, getString(R.string.journal_item_birthday), null, getDisplayedDate(contact.birthDay?.date, contact.birthDay?.partialDate))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RELATED
|
||||||
|
for (related in contact.relations) {
|
||||||
|
val types = related.types
|
||||||
|
val type = if (types.size > 0) types[0].value else null
|
||||||
|
addInfoItem(view.context, aboutCard, getString(R.string.journal_item_relation), type, related.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHOTO
|
||||||
|
// if (contact.photo != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDisplayedDate(date: Date?, partialDate: PartialDate?): String? {
|
||||||
|
if (date != null) {
|
||||||
|
val epochDate = date.time
|
||||||
|
return getDisplayedDatetime(epochDate, epochDate, true, context)
|
||||||
|
} else if (partialDate != null){
|
||||||
|
val formatter = SimpleDateFormat("d MMMM", Locale.getDefault())
|
||||||
|
val calendar = GregorianCalendar()
|
||||||
|
calendar.set(Calendar.DAY_OF_MONTH, partialDate.date!!)
|
||||||
|
calendar.set(Calendar.MONTH, partialDate.month!! - 1)
|
||||||
|
return formatter.format(calendar.time)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun addInfoItem(context: Context, parent: ViewGroup, type: String, label: String?, value: String?): View {
|
||||||
|
val layout = parent.findViewById<View>(R.id.container) as ViewGroup
|
||||||
|
val infoItem = LayoutInflater.from(context).inflate(R.layout.contact_info_item, layout, false)
|
||||||
|
layout.addView(infoItem)
|
||||||
|
setTextViewText(infoItem, R.id.type, type)
|
||||||
|
setTextViewText(infoItem, R.id.title, label)
|
||||||
|
setTextViewText(infoItem, R.id.content, value)
|
||||||
|
parent.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
return infoItem
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setTextViewText(parent: View, id: Int, text: String?) {
|
||||||
|
val tv = parent.findViewById<View>(id) as TextView
|
||||||
|
if (text == null) {
|
||||||
|
tv.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
tv.text = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDisplayedDatetime(startMillis: Long, endMillis: Long, allDay: Boolean, context: Context?): String? {
|
||||||
|
// Configure date/time formatting.
|
||||||
|
val flagsDate = DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_SHOW_WEEKDAY
|
||||||
|
var flagsTime = DateUtils.FORMAT_SHOW_TIME
|
||||||
|
if (DateFormat.is24HourFormat(context)) {
|
||||||
|
flagsTime = flagsTime or DateUtils.FORMAT_24HOUR
|
||||||
|
}
|
||||||
|
|
||||||
|
val datetimeString: String
|
||||||
|
if (allDay) {
|
||||||
|
// For multi-day allday events or single-day all-day events that are not
|
||||||
|
// today or tomorrow, use framework formatter.
|
||||||
|
|
||||||
|
// We need to remove 24hrs because full day events are from the start of a day until the start of the next
|
||||||
|
var adjustedEnd = endMillis - 24 * 60 * 60 * 1000;
|
||||||
|
if (adjustedEnd < startMillis) {
|
||||||
|
adjustedEnd = startMillis;
|
||||||
|
}
|
||||||
|
val f = Formatter(StringBuilder(50), Locale.getDefault())
|
||||||
|
datetimeString = DateUtils.formatDateRange(context, f, startMillis,
|
||||||
|
adjustedEnd, flagsDate).toString()
|
||||||
|
} else {
|
||||||
|
// For multiday events, shorten day/month names.
|
||||||
|
// Example format: "Fri Apr 6, 5:00pm - Sun, Apr 8, 6:00pm"
|
||||||
|
val flagsDatetime = flagsDate or flagsTime or DateUtils.FORMAT_ABBREV_MONTH or
|
||||||
|
DateUtils.FORMAT_ABBREV_WEEKDAY
|
||||||
|
datetimeString = DateUtils.formatDateRange(context, startMillis, endMillis,
|
||||||
|
flagsDatetime)
|
||||||
|
}
|
||||||
|
return datetimeString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ import android.view.ViewGroup
|
|||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.fragment.app.ListFragment
|
import androidx.fragment.app.ListFragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import androidx.fragment.app.commit
|
||||||
import com.etesync.syncadapter.CachedCollection
|
import com.etesync.syncadapter.CachedCollection
|
||||||
import com.etesync.syncadapter.CachedItem
|
import com.etesync.syncadapter.CachedItem
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
@ -60,8 +61,10 @@ class ListEntriesFragment : ListFragment(), AdapterView.OnItemClickListener {
|
|||||||
|
|
||||||
override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||||
val item = listAdapter?.getItem(position) as CachedItem
|
val item = listAdapter?.getItem(position) as CachedItem
|
||||||
Toast.makeText(context, "Clicked ${item.item.uid}", Toast.LENGTH_LONG).show()
|
activity?.supportFragmentManager?.commit {
|
||||||
// startActivity(JournalItemActivity.newIntent(requireContext(), account, info, entry.content))
|
replace(R.id.fragment_container, CollectionItemFragment(item))
|
||||||
|
addToBackStack(EditCollectionFragment::class.java.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal inner class EntriesListAdapter(context: Context, val cachedCollection: CachedCollection) : ArrayAdapter<CachedItem>(context, R.layout.journal_viewer_list_item) {
|
internal inner class EntriesListAdapter(context: Context, val cachedCollection: CachedCollection) : ArrayAdapter<CachedItem>(context, R.layout.journal_viewer_list_item) {
|
||||||
|
26
app/src/main/res/menu/collection_item_fragment.xml
Normal file
26
app/src/main/res/menu/collection_item_fragment.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?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">
|
||||||
|
|
||||||
|
<group android:id="@+id/journal_item_menu_event_invite">
|
||||||
|
<item android:title="@string/calendar_attendees_send_email_action"
|
||||||
|
android:id="@+id/on_send_event_invite"
|
||||||
|
android:icon="@drawable/ic_email_black"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group android:id="@+id/journal_item_menu_restore">
|
||||||
|
<item android:title="@string/journal_item_restore_action"
|
||||||
|
android:icon="@drawable/ic_restore_black"
|
||||||
|
android:id="@+id/on_restore_item"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
</group>
|
||||||
|
</menu>
|
Loading…
Reference in New Issue
Block a user