at the moment, i'm using single fragments or activities together with firebase ui and two-way databinding to display and edit my firestore data.
After downloading data from firebase in suspend fun, i call "binding.data = document".
Then i hide the ContentLoadingProgressBar and make the NestedScrollView visible.
After editing all textfields i collect the data with "Serializer().serialize(binding.data)" and forward it to my firebase upload service.
Now the question:
If i'm using ViewPager2 with TabLayout (see developer.android.com), how can i connect my firestore document to all "binding.data" of all tab fragments at the same time, so i can edit different parts of data in different tabs and collect them all at the end with "Serializer().serialize(binding.data)" to upload them?
Thanks in advance for your help!
Kotlin class containing data (compatible with Firestore up- and download)
package com.project.items.firestore
import android.text.format.DateFormat
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import com.google.firebase.firestore.DocumentId
import com.google.firebase.firestore.Exclude
import com.project.BR
import java.util.*
class ArticleFirestoreDocument : BaseObservable() {
companion object {
fun build(
id: String,
ueberschrift: String,
kategorie: String,
zeit: Date,
inhalt: String,
links: ArrayList<String>,
bilder: ArrayList<String>,
visibility: String
): ArticleFirestoreDocument {
val document = ArticleFirestoreDocument()
document.id = id
document.ueberschrift = ueberschrift
document.kategorie = kategorie
document.zeit = zeit
document.inhalt = inhalt
document.links = links
document.bilder = bilder
document.visibility = visibility
return document
}
}
@DocumentId
@get:Bindable
var id: String = ""
set(value) {
if (field != value) {
field = value
notifyPropertyChanged(BR.id)
}
}
@get:Bindable
var ueberschrift: String = ""
set(value) {
if (field != value) {
field = value
notifyPropertyChanged(BR.ueberschrift)
}
}
@get:Bindable
var kategorie: String = ""
set(value) {
if (field != value) {
field = value
notifyPropertyChanged(BR.kategorie)
}
}
@get:Bindable
var zeit: Date = Date()
set(value) {
if (field != value) {
field = value
notifyPropertyChanged(BR.zeit)
}
}
@get:Bindable
var inhalt: String = ""
set(value) {
if (field != value) {
field = value
notifyPropertyChanged(BR.inhalt)
}
}
@get:Bindable
var links: ArrayList<String> = arrayListOf()
set(value) {
if (field != value) {
field = value
notifyPropertyChanged(BR.links)
}
}
@get:Bindable
var bilder: ArrayList<String> = arrayListOf()
set(value) {
if (field != value) {
field = value
notifyPropertyChanged(BR.bilder)
}
}
@get:Bindable
var visibility: String = ""
set(value) {
if (field != value) {
field = value
notifyPropertyChanged(BR.visibility)
}
}
fun getDateTime(date: Date?): String {
return if (date != null) {
val cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Berlin"))
cal.time = date
DateFormat.format("EEEE dd.MM.yyyy HH:mm", cal).toString() + " Uhr"
} else {
""
}
}
fun getDateTimeShort(date: Date?): String {
return if (date != null) {
val cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Berlin"))
cal.time = date
DateFormat.format("E dd.MM.yy HH:mm", cal).toString() + " Uhr"
} else {
""
}
}
fun getDate(date: Date?): String {
return if (date != null) {
val cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Berlin"))
cal.time = date
DateFormat.format("dd.MM.yyyy", cal).toString()
} else {
""
}
}
fun getTime(date: Date?): String {
return if (date != null) {
val cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Berlin"))
cal.time = date
DateFormat.format("HH:mm", cal).toString() + " Uhr"
} else {
""
}
}
@Exclude
fun getEmojiText(): String {
return ("${this.ueberschrift}\n\n" +
"\uD83D\uDCC5 Datum: ${getDate(this.zeit)}\n" +
"\uD83D\uDD50 Uhrzeit: ${getTime(this.zeit)}\n" +
"\uD83D\uDDC3 Kategorie: ${this.kategorie}\n\n" +
"\uD83D\uDCDD ${this.inhalt.replace("[ ]*\\\\n[ ]*".toRegex(), "\n").replace("\\\\t".toRegex(), "\t").trim()}\n\n" +
this.links.joinToString(separator = "\n"))
.trim()
}
}
XML Layout (with data variable "ArticleFirestoreDocument" and two-way databinding, e.g. "@={data.kategorie}")
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="data"
type="com.project.items.firestore.ArticleFirestoreDocument" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/toolbar"
layout="@layout/include_material_toolbar_edit"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.core.widget.NestedScrollView
android:id="@+id/nsv"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?attr/colorSurface"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:orientation="vertical">
<include
android:id="@+id/visibility"
layout="@layout/include_material_textfield_clickable_icon"
app:hint="@{@string/hint_rule}"
app:icon="@{@drawable/ic_outline_rule_24}"
app:iconDescription="@{@string/icon_rule}"
app:text="@={data.visibility}" />
<include
android:id="@+id/headline"
layout="@layout/include_material_textfield"
app:hint="@{@string/hint_headline}"
app:text="@={data.ueberschrift}" />
<include
android:id="@+id/category"
layout="@layout/include_material_textfield_clickable_icon"
app:hint="@{@string/hint_category}"
app:icon="@{@drawable/ic_outline_category_24}"
app:iconDescription="@{@string/icon_category}"
app:text="@={data.kategorie}" />
<include
android:id="@+id/content"
layout="@layout/include_material_textfield_icon"
app:hint="@{@string/hint_content}"
app:icon="@{@drawable/ic_outline_notes_24}"
app:iconDescription="@{@string/icon_notes}"
app:text="@={data.inhalt}" />
<include
android:id="@+id/links"
layout="@layout/include_material_textfield_icon_end"
app:hint="@{@string/hint_link}"
app:icon="@{@drawable/ic_outline_link_24}"
app:iconDescription="@{@string/icon_link}"
app:iconEnd="@{@drawable/ic_outline_add_24}"
app:iconEndDescription="@{@string/icon_add}" />
<include
android:id="@+id/links_recyclerview"
layout="@layout/include_material_recyclerview"
app:isBottom="@{false}"
app:isDivider="@{false}"
app:isFull="@{false}" />
<include
android:id="@+id/pictures"
layout="@layout/include_material_textfield_clickable_icon"
app:icon="@{@drawable/ic_outline_photo_24}"
app:iconDescription="@{@string/icon_photo}"
app:text="@{@string/hint_images + @string/append_select}" />
<include
android:id="@+id/pictures_recyclerview"
layout="@layout/include_material_recyclerview_horizontal"
app:isBottom="@{true}"
app:isDivider="@{false}"
app:isFull="@{true}" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/clpb"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>