diff --git a/app/src/main/java/com/etesync/syncadapter/ui/etebase/CollectionItemFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/etebase/CollectionItemFragment.kt index a42f4f14..dd2b8398 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/etebase/CollectionItemFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/etebase/CollectionItemFragment.kt @@ -56,7 +56,7 @@ class CollectionItemFragment(private val cachedItem: CachedItem) : Fragment() { val tabLayout = v.findViewById(R.id.tabs) tabLayout.setupWithViewPager(viewPager) - ListEntriesFragment.setItemView(v.findViewById(R.id.journal_list_item), cachedCollection.meta.collectionType, cachedItem) + v.findViewById(R.id.journal_list_item).visibility = View.GONE } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { @@ -69,22 +69,26 @@ private class TabsAdapter(fm: FragmentManager, private val context: Context, pri override fun getCount(): Int { // FIXME: Make it depend on info enumType (only have non-raw for known types) - return 2 + return 3 } override fun getPageTitle(position: Int): CharSequence? { return if (position == 0) { context.getString(R.string.journal_item_tab_main) - } else { + } else if (position == 1) { context.getString(R.string.journal_item_tab_raw) + } else { + context.getString(R.string.journal_item_tab_revisions) } } override fun getItem(position: Int): Fragment { return if (position == 0) { PrettyFragment(cachedCollection, cachedItem.content) - } else { + } else if (position == 1) { TextFragment(cachedItem.content) + } else { + ItemRevisionsListFragment(cachedCollection, cachedItem) } } } diff --git a/app/src/main/java/com/etesync/syncadapter/ui/etebase/ItemRevisionsListFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/etebase/ItemRevisionsListFragment.kt new file mode 100644 index 00000000..4f4ee7a9 --- /dev/null +++ b/app/src/main/java/com/etesync/syncadapter/ui/etebase/ItemRevisionsListFragment.kt @@ -0,0 +1,147 @@ +package com.etesync.syncadapter.ui.etebase + +import android.content.Context +import android.os.Bundle +import android.os.Parcelable +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.TextView +import androidx.fragment.app.ListFragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.commit +import androidx.fragment.app.viewModels +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.observe +import com.etebase.client.FetchOptions +import com.etesync.syncadapter.CachedCollection +import com.etesync.syncadapter.CachedItem +import com.etesync.syncadapter.R +import com.etesync.syncadapter.ui.etebase.ListEntriesFragment.Companion.setItemView +import org.jetbrains.anko.doAsync +import org.jetbrains.anko.uiThread +import java.util.* +import java.util.concurrent.Future + + +class ItemRevisionsListFragment(private val cachedCollection: CachedCollection, private val cachedItem: CachedItem) : ListFragment(), AdapterView.OnItemClickListener { + private val model: AccountViewModel by activityViewModels() + private val revisionsModel: RevisionsViewModel by viewModels() + private var state: Parcelable? = 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(android.R.id.empty) as TextView + + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + var restored = false + + revisionsModel.loadRevisions(model.value!!, cachedCollection, cachedItem) + revisionsModel.observe(this) { + val entries = it.sortedByDescending { item -> + item.meta.mtime ?: 0 + } + val listAdapter = EntriesListAdapter(requireContext(), cachedCollection) + setListAdapter(listAdapter) + + listAdapter.addAll(entries) + + if(!restored && (state != null)) { + listView.onRestoreInstanceState(state) + restored = true + } + + emptyTextView!!.text = getString(R.string.journal_entries_list_empty) + } + + listView.onItemClickListener = this + } + override fun onPause() { + state = listView.onSaveInstanceState() + super.onPause() + } + + override fun onDestroyView() { + super.onDestroyView() + revisionsModel.cancelLoad() + } + + override fun onItemClick(parent: AdapterView<*>, view: View, position: Int, id: Long) { + val item = listAdapter?.getItem(position) as CachedItem + activity?.supportFragmentManager?.commit { + replace(R.id.fragment_container, CollectionItemFragment(item)) + addToBackStack(null) + } + } + + internal inner class EntriesListAdapter(context: Context, val cachedCollection: CachedCollection) : ArrayAdapter(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(R.id.error) as ImageView + errorIcon.visibility = View.VISIBLE + } + */ + + return v + } + } +} + + +class RevisionsViewModel : ViewModel() { + private val revisions = MutableLiveData>() + private var asyncTask: Future? = null + + fun loadRevisions(accountCollectionHolder: AccountHolder, cachedCollection: CachedCollection, cachedItem: CachedItem) { + asyncTask = doAsync { + val ret = LinkedList() + val col = cachedCollection.col + val itemManager = accountCollectionHolder.colMgr.getItemManager(col) + var iterator: String? = null + var done = false + while (!done) { + val chunk = itemManager.itemRevisions(cachedItem.item, FetchOptions().iterator(iterator).limit(30)) + iterator = chunk.iterator + done = chunk.isDone + + ret.addAll(chunk.data.map { CachedItem(it, it.meta, it.contentString) }) + } + + uiThread { + revisions.value = ret + } + } + } + + fun cancelLoad() { + asyncTask?.cancel(true) + } + + fun observe(owner: LifecycleOwner, observer: (List) -> Unit) = + revisions.observe(owner, observer) +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 667b7373..388ff1c6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -171,6 +171,7 @@ About Main + Revisions Raw Attendees Reminders