Ersetze ParseObjects mit Parse Subclasses + ändere Naming Convention

master
Niko Diamadis 4 years ago
parent 16fbfaee4d
commit 5ecfa44efa
Signed by: niko
GPG Key ID: BE53B0B17B1B142E

@ -1,12 +1,22 @@
package com.cyb3rko.techniklogger
import android.app.Application
import com.cyb3rko.techniklogger.data.objects.Member
import com.cyb3rko.techniklogger.data.objects.Mission
import com.cyb3rko.techniklogger.data.objects.Participation
import com.cyb3rko.techniklogger.data.objects.Year
import com.parse.Parse
import com.parse.ParseObject
class App : Application() {
override fun onCreate() {
super.onCreate()
ParseObject.registerSubclass(Member::class.java)
ParseObject.registerSubclass(Mission::class.java)
ParseObject.registerSubclass(Participation::class.java)
ParseObject.registerSubclass(Year::class.java)
if (BuildConfig.DEBUG) Parse.setLogLevel(Parse.LOG_LEVEL_DEBUG) else Parse.setLogLevel(Parse.LOG_LEVEL_NONE)
Parse.initialize(Parse.Configuration.Builder(this)
.applicationId("technik-logger")

@ -12,23 +12,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
internal const val CLASS_EINSATZ = "Einsatz"
internal const val CLASS_JAHR = "Jahr"
internal const val CLASS_TECHNIKER = "Techniker"
internal const val CLASS_TEILNAHME = "Teilnahme"
internal const val COLUMN_EINSATZ_DATUM = "datum"
internal const val COLUMN_EINSATZ_DAUER = "dauer"
internal const val COLUMN_EINSATZ_JAHR = "jahr"
internal const val COLUMN_TEILNAHME_VON = "von"
internal const val COLUMN_TEILNAHME_AN = "an"
internal const val COLUMN_EINSATZ_NAME = "name"
internal const val COLUMN_EINSATZ_ORT = "ort"
internal const val COLUMN_EINSATZ_UHRZEIT = "uhrzeit"
internal const val COLUMN_TEILNAHME_DAUER = "dauer"
internal const val COLUMN_TEILNAHME_UHRZEIT = "uhrzeit"
internal const val COLUMN_JAHR_NAME = "name"
internal const val COLUMN_TECHNIKER_ADMIN = "admin"
internal const val COLUMN_TECHNIKER_ENTLASSEN = "entlassen"
internal const val COLUMN_TECHNIKER_NAME = "name"
internal const val CURRENT_YEAR = "current_year"
internal const val CURRENT_YEAR_NAME = "current_year_name"

@ -1,12 +0,0 @@
package com.cyb3rko.techniklogger.data
import java.util.*
data class Mission(
val date: Date,
val duration: String,
val location: String,
val name: String,
val objectId: String,
val time: String
)

@ -1,64 +1,61 @@
package com.cyb3rko.techniklogger.data
import com.cyb3rko.techniklogger.*
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_DATUM
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_DAUER
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_JAHR
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_NAME
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_ORT
import com.cyb3rko.techniklogger.data.objects.Member
import com.cyb3rko.techniklogger.data.objects.Mission
import com.cyb3rko.techniklogger.data.objects.Participation
import com.cyb3rko.techniklogger.data.objects.Year
import com.parse.ParseException
import com.parse.ParseObject
import com.parse.ParseQuery
import java.text.SimpleDateFormat
import java.util.*
object ParseController {
private fun <T : ParseObject>getQuery(
className: String,
private inline fun <reified T : ParseObject>getQuery(
allowCache: Boolean = true
): ParseQuery<T> {
return ParseQuery<T>(className).apply {
return ParseQuery(T::class.java).apply {
limit = -1
cachePolicy = if (allowCache) {
ParseQuery.CachePolicy.CACHE_THEN_NETWORK
} else ParseQuery.CachePolicy.NETWORK_ONLY
} else {
ParseQuery.CachePolicy.NETWORK_ONLY
}
}
}
internal fun fetchAdminStatus(
userName: String?,
name: String?,
action: (objectId: String?, admin: Boolean?, e: ParseException?) -> Unit
) {
val query = getQuery<ParseObject>("Techniker", false)
query.whereEqualTo("name", userName)
query.getFirstInBackground { techniker, e ->
val query = getQuery<Member>(false)
query.whereEqualTo(Member.COLUMN_NAME, name)
query.getFirstInBackground { member, e ->
if (e == null) {
action(techniker.objectId, techniker.getBoolean("admin"), e)
action(member.objectId, member.admin, e)
} else {
action(null, null, e)
}
}
}
internal fun fetchYears(action: (entries: List<ParseObject>, e: ParseException?) -> Unit) {
val query = getQuery<ParseObject>("Jahr")
query.orderByDescending(COLUMN_JAHR_NAME)
query.findInBackground { entries, e ->
internal fun fetchYears(action: (entries: List<Year>, e: ParseException?) -> Unit) {
val query = getQuery<Year>()
query.orderByDescending(Year.COLUMN_NAME)
query.findInBackground { years, e ->
if (e == null) {
action(entries, null)
action(years, null)
} else action(listOf(), e)
}
}
internal fun fetchMission(
objectId: String?,
action: (entry: ParseObject?, e: ParseException?) -> Unit
action: (mission: Mission?, e: ParseException?) -> Unit
) {
val query = getQuery<ParseObject>(CLASS_EINSATZ)
query.getInBackground(objectId) { entry, e ->
val query = getQuery<Mission>()
query.getInBackground(objectId) { mission, e ->
if (e == null) {
action(entry, null)
action(mission, null)
} else {
action(null, e)
}
@ -66,89 +63,56 @@ object ParseController {
}
internal fun fetchMissions(
year: String?,
year: String,
action: (missions: List<Mission>, e: ParseException?) -> Unit
) {
val query = getQuery<ParseObject>("Einsatz")
query.orderByDescending(COLUMN_EINSATZ_DATUM)
query.whereEqualTo(
COLUMN_EINSATZ_JAHR,
ParseObject.createWithoutData(
"Jahr",
year
)
)
query.findInBackground { objects, e ->
val query = getQuery<Mission>()
query.orderByDescending(Mission.COLUMN_DATE)
query.whereEqualTo(Mission.COLUMN_YEAR, Year.emptyObject(year))
query.findInBackground { missions, e ->
if (e == null) {
val data = mutableListOf<Mission>()
objects.forEach {
val dates = it.getString(COLUMN_EINSATZ_DATUM)!!.split(",")
val time = if (dates.size > 1) dates[1] else ""
data.add(
Mission(
SimpleDateFormat("yyyy.MM.dd", Locale.GERMANY).parse(dates[0])!!,
it.getInt(COLUMN_EINSATZ_DAUER).toString(),
it.getString(COLUMN_EINSATZ_ORT)!!,
it.getString(COLUMN_EINSATZ_NAME)!!,
it.objectId,
time
)
)
}
action(data, null)
action(missions, null)
} else {
action(listOf(), e)
}
}
}
internal fun fetchParticipation(
missionId: String,
technikerId: String,
action: (entry: ParseObject?, e: ParseException?) -> Unit
) {
val query = getQuery<ParseObject>(CLASS_TEILNAHME, false)
query.whereEqualTo(COLUMN_TEILNAHME_AN, ParseObject.createWithoutData(CLASS_EINSATZ, missionId))
query.whereEqualTo(COLUMN_TEILNAHME_VON, ParseObject.createWithoutData(CLASS_EINSATZ, technikerId))
query.getFirstInBackground { entry, e ->
if (e == null) {
action(entry, null)
} else action(null, e)
}
}
internal fun fetchParticipations(
missionId: String,
includeTechniker: Boolean,
action: (entries: List<ParseObject>, e: ParseException?) -> Unit
includeMember: Boolean,
action: (participations: List<Participation>, e: ParseException?) -> Unit
) {
val query = getQuery<ParseObject>(CLASS_TEILNAHME, false)
query.whereEqualTo("an", ParseObject.createWithoutData(CLASS_EINSATZ, missionId))
if (includeTechniker) query.include("von")
query.findInBackground { entries, e ->
val query = getQuery<Participation>(false)
query.whereEqualTo(Participation.COLUMN_IN, Mission.emptyObject(missionId))
if (includeMember) query.include(Participation.COLUMN_BY)
query.findInBackground { participations, e ->
if (e == null) {
action(entries, null)
} else action(listOf(), e)
if (includeMember) participations.sortBy { it.name }
action(participations, null)
} else {
action(listOf(), e)
}
}
}
internal fun fetchTechniker(
internal fun fetchMembers(
action: (
techniker: List<ParseObject>,
technikerNames: List<String>,
members: List<Member>,
memberNames: List<String>,
e: ParseException?
) -> Unit
) {
val query = getQuery<ParseObject>(CLASS_TECHNIKER, false)
query.whereEqualTo(COLUMN_TECHNIKER_ENTLASSEN, false)
query.orderByAscending(COLUMN_TECHNIKER_NAME)
query.findInBackground { objects, e ->
val query = getQuery<Member>(false)
query.whereEqualTo(Member.COLUMN_RETIRED, false)
query.orderByAscending(Member.COLUMN_NAME)
query.findInBackground { members, e ->
if (e == null) {
val techniker = mutableListOf<String>()
objects.forEach {
techniker.add(it.getString(COLUMN_TECHNIKER_NAME)!!)
val names = mutableListOf<String>()
members.forEach {
names.add(it.name)
}
action(objects, techniker, null)
action(members, names, null)
} else {
action(listOf(), listOf(), e)
}

@ -1,9 +0,0 @@
package com.cyb3rko.techniklogger.data
data class Participation(
var dauer: String,
val name: String,
val objectId: String,
var teilnahmeKey: String,
var uhrzeit: String
)

@ -1,6 +0,0 @@
package com.cyb3rko.techniklogger.data
data class Year(
val name: String,
val objectId: String
)

@ -0,0 +1,38 @@
package com.cyb3rko.techniklogger.data.objects
import com.cyb3rko.techniklogger.data.objects.Member.Companion.CLASS_NAME
import com.parse.ParseClassName
import com.parse.ParseObject
@ParseClassName(CLASS_NAME)
internal class Member : ParseObject() {
internal val admin
get() = getBoolean(COLUMN_ADMIN)
internal val name
get() = getString(COLUMN_NAME)!!
internal fun setAdmin(admin: Boolean) {
put(COLUMN_ADMIN, admin)
}
internal fun setName(name: String) {
put(COLUMN_NAME, name)
}
internal fun retire() {
put(COLUMN_RETIRED, true)
}
companion object {
internal const val CLASS_NAME = "Techniker"
private const val COLUMN_ADMIN = "admin"
internal const val COLUMN_RETIRED = "entlassen"
internal const val COLUMN_NAME = "name"
internal fun emptyObject(objectId: String): Member {
return createWithoutData(Member::class.java, objectId)
}
}
}

@ -0,0 +1,65 @@
package com.cyb3rko.techniklogger.data.objects
import com.cyb3rko.techniklogger.data.objects.Mission.Companion.CLASS_NAME
import com.parse.ParseClassName
import com.parse.ParseObject
import java.text.SimpleDateFormat
import java.util.*
@ParseClassName(CLASS_NAME)
internal class Mission : ParseObject() {
internal val date: () -> Date
get() = {
val dates = getString(COLUMN_DATE)!!.split(",")
SimpleDateFormat("yyyy.MM.dd", Locale.GERMANY).parse(dates[0])!!
}
internal val duration
get() = getDouble(COLUMN_DURATION).toFloat()
internal val location
get() = getString(COLUMN_LOCATION)!!
internal val name
get() = getString(COLUMN_NAME)!!
internal val time: () -> String
get() = {
val dates = getString(COLUMN_DATE)!!.split(",")
if (dates.size > 1) dates[1] else ""
}
internal fun setDate(date: String) {
put(COLUMN_DATE, date)
}
internal fun setDuration(duration: Float) {
put(COLUMN_DURATION, duration)
}
internal fun setLocation(location: String) {
put(COLUMN_LOCATION, location)
}
internal fun setName(name: String) {
put(COLUMN_NAME, name)
}
internal fun setYear(yearId: String) {
put(COLUMN_YEAR, Year.emptyObject(yearId))
}
companion object {
internal const val CLASS_NAME = "Einsatz"
internal const val COLUMN_DATE = "datum"
private const val COLUMN_DURATION = "dauer"
private const val COLUMN_LOCATION = "ort"
private const val COLUMN_NAME = "name"
internal const val COLUMN_YEAR = "jahr"
internal fun emptyObject(objectId: String): Mission {
return createWithoutData(Mission::class.java, objectId)
}
}
}

@ -0,0 +1,44 @@
package com.cyb3rko.techniklogger.data.objects
import com.cyb3rko.techniklogger.data.objects.Participation.Companion.CLASS_NAME
import com.parse.ParseClassName
import com.parse.ParseObject
@ParseClassName(CLASS_NAME)
internal class Participation : ParseObject() {
internal val by
get() = getParseObject(COLUMN_BY)?.objectId
internal val duration
get() = getDouble(COLUMN_DURATION).toFloat()
internal val `in`
get() = getParseObject(COLUMN_IN)?.objectId
internal val name
get() = (getParseObject(COLUMN_BY) as Member).name
internal val time
get() = getString(COLUMN_TIME)!!
internal fun setDuration(duration: Float) {
put(COLUMN_DURATION, duration)
}
internal fun setTime(time: String) {
put(COLUMN_TIME, time)
}
companion object {
internal const val CLASS_NAME = "Teilnahme"
internal const val COLUMN_BY = "von"
private const val COLUMN_DURATION = "dauer"
internal const val COLUMN_IN = "an"
private const val COLUMN_TIME = "uhrzeit"
internal fun emptyObject(objectId: String): Participation {
return createWithoutData(Participation::class.java, objectId)
}
}
}

@ -0,0 +1,21 @@
package com.cyb3rko.techniklogger.data.objects
import com.cyb3rko.techniklogger.data.objects.Year.Companion.CLASS_NAME
import com.parse.ParseClassName
import com.parse.ParseObject
@ParseClassName(CLASS_NAME)
internal class Year : ParseObject() {
internal val name
get() = getString(COLUMN_NAME)!!
companion object {
internal const val CLASS_NAME = "Jahr"
internal const val COLUMN_NAME = "name"
internal fun emptyObject(objectId: String): Year {
return createWithoutData(Year::class.java, objectId)
}
}
}

@ -29,7 +29,7 @@ class ListingFragment : Fragment() {
private lateinit var myContext: Context
private var adminMode: Boolean? = null
private lateinit var projectsAdapter: MissionAdapter
private lateinit var missionAdapter: MissionAdapter
private var isFABOpen = false
private lateinit var sharedPref: SharedPreferences
private lateinit var sharedPrefEditor: SharedPreferences.Editor
@ -51,18 +51,18 @@ class ListingFragment : Fragment() {
binding.loadingAnimation.playAnimation()
projectsAdapter = MissionAdapter({ objectId: String ->
missionAdapter = MissionAdapter({ objectId: String ->
val action = ListingFragmentDirections.navigateToProject(objectId)
findNavController().navigate(action)
}, {
if (adminMode != null && adminMode!!) {
val action = ListingFragmentDirections.navigateToPusher(
date = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(it.date),
date = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(it.date()),
duration = it.duration,
location = it.location,
name = it.name,
objectId = it.objectId,
time = it.time
time = it.time()
)
findNavController().navigate(action)
true
@ -71,7 +71,7 @@ class ListingFragment : Fragment() {
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(myContext)
adapter = projectsAdapter
adapter = missionAdapter
}
loadEntries()
@ -97,7 +97,7 @@ class ListingFragment : Fragment() {
closeFABMenu()
ExportBuilder(
myContext,
projectsAdapter.currentList,
missionAdapter.currentList,
binding,
sharedPref.getString("current_year_name", "")!!
)
@ -138,21 +138,19 @@ class ListingFragment : Fragment() {
if (empty) {
null
} else {
projectsAdapter.currentList.size.toString()
missionAdapter.currentList.size.toString()
}
)
}
private fun loadEntries() {
ParseController.fetchMissions(
sharedPref.getString(CURRENT_YEAR, "")
) { entries, e ->
ParseController.fetchMissions(sharedPref.getString(CURRENT_YEAR, "")!!) { missions, e ->
if (e == null) {
showAnimation(false)
binding.swipeRefreshLayout.isRefreshing = false
projectsAdapter.submitList(entries)
missionAdapter.submitList(missions)
projectsAdapter.registerAdapterDataObserver(object: RecyclerView.AdapterDataObserver() {
missionAdapter.registerAdapterDataObserver(object: RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
super.onItemRangeInserted(positionStart, itemCount)
binding.recyclerView.smoothScrollToPosition(0)
@ -162,7 +160,7 @@ class ListingFragment : Fragment() {
if (e.message != null) {
if (e.message != "results not cached") {
binding.swipeRefreshLayout.isRefreshing = false
if (projectsAdapter.currentList.isEmpty()) {
if (missionAdapter.currentList.isEmpty()) {
showAnimation(true, false)
}
Toasty.error(myContext, "Abruf fehlgeschlagen", Toasty.LENGTH_SHORT).show()

@ -13,24 +13,19 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.callbacks.onDismiss
import com.afollestad.materialdialogs.customview.customView
import com.androidnetworking.AndroidNetworking.put
import com.cyb3rko.techniklogger.*
import com.cyb3rko.techniklogger.CLASS_TECHNIKER
import com.cyb3rko.techniklogger.COLUMN_TECHNIKER_ADMIN
import com.cyb3rko.techniklogger.COLUMN_TECHNIKER_ENTLASSEN
import com.cyb3rko.techniklogger.COLUMN_TECHNIKER_NAME
import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.data.objects.Member
import com.cyb3rko.techniklogger.data.ParseController
import com.cyb3rko.techniklogger.databinding.FragmentManageTechnikerBinding
import com.cyb3rko.techniklogger.databinding.FragmentManageMembersBinding
import com.google.android.material.switchmaterial.SwitchMaterial
import com.google.android.material.textfield.TextInputEditText
import com.parse.ParseObject
import es.dmoral.toasty.Toasty
class ManageTechnikerFragment : Fragment() {
private var _binding: FragmentManageTechnikerBinding? = null
class ManageMembersFragment : Fragment() {
private var _binding: FragmentManageMembersBinding? = null
private lateinit var myContext: Context
private val technikerNames = mutableListOf<String>()
private val memberNames = mutableListOf<String>()
private val binding get() = _binding!!
@ -39,28 +34,29 @@ class ManageTechnikerFragment : Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentManageTechnikerBinding.inflate(inflater, container, false)
_binding = FragmentManageMembersBinding.inflate(inflater, container, false)
val root = binding.root
myContext = requireContext()
loadTechniker()
loadMembers()
binding.fab.setOnClickListener {
MaterialDialog(myContext, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(text = "Techniker hinzufügen")
customView(R.layout.techniker_dialog, horizontalPadding = true)
customView(R.layout.member_dialog, horizontalPadding = true)
positiveButton(text = "Hinzufügen") {
val view = it.view
val newName = view.findViewById<TextInputEditText>(R.id.name).text.toString()
val newAdmin = view.findViewById<SwitchMaterial>(R.id.admin).isChecked
ParseObject.create(CLASS_TECHNIKER).apply {
put(COLUMN_TECHNIKER_NAME, newName)
put(COLUMN_TECHNIKER_ADMIN, newAdmin)
Member().apply {
setAdmin(newAdmin)
setName(newName)
saveInBackground {
if (it == null) {
Toasty.success(myContext, "Hinzugefügt").show()
showAnimation(true)
loadTechniker()
loadMembers()
} else {
Toasty.error(myContext, "Fehler bei Speicherung").show()
Log.e("TechnikLogger.Techniker", it.message.toString())
@ -77,35 +73,35 @@ class ManageTechnikerFragment : Fragment() {
setOnRefreshListener {
isRefreshing = false
showAnimation(true)
loadTechniker()
loadMembers()
}
}
return root
}
private fun loadTechniker() {
technikerNames.clear()
private fun loadMembers() {
memberNames.clear()
binding.list.adapter = ArrayAdapter(
myContext,
android.R.layout.simple_list_item_1,
technikerNames
memberNames
)
ParseController.fetchTechniker { techniker, technikerNames, e ->
ParseController.fetchMembers { members, memberNames, e ->
if (e == null) {
val adapter = ArrayAdapter(
myContext,
android.R.layout.simple_list_item_1,
technikerNames
memberNames
)
binding.list.adapter = adapter
showAnimation(false)
binding.list.setOnItemClickListener { _, _, index, _ ->
val dialogView = layoutInflater.inflate(R.layout.techniker_dialog, null)
dialogView.findViewById<TextInputEditText>(R.id.name).setText(technikerNames[index])
dialogView.findViewById<SwitchMaterial>(R.id.admin).isChecked = techniker[index].getBoolean(COLUMN_TECHNIKER_ADMIN)
val dialogView = layoutInflater.inflate(R.layout.member_dialog, null)
dialogView.findViewById<TextInputEditText>(R.id.name).setText(memberNames[index])
dialogView.findViewById<SwitchMaterial>(R.id.admin).isChecked = members[index].admin
MaterialDialog(myContext, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(text = "Techniker-Info")
customView(0, dialogView, horizontalPadding = true)
@ -113,18 +109,21 @@ class ManageTechnikerFragment : Fragment() {
val view = it.view
val newName = view.findViewById<TextInputEditText>(R.id.name).text.toString()
val newAdmin = view.findViewById<SwitchMaterial>(R.id.admin).isChecked
val parseObject = techniker[index]
if (newName != parseObject.getString(COLUMN_TECHNIKER_NAME) ||
newAdmin != parseObject.getBoolean(COLUMN_TECHNIKER_ADMIN)
) {
parseObject.apply {
put(COLUMN_TECHNIKER_NAME, newName)
put(COLUMN_TECHNIKER_ADMIN, newAdmin)
val member = members[index]
val adminChanged = newAdmin != member.admin
val nameChanged = newName != member.name
if (adminChanged || nameChanged) {
member.apply {
setAdmin(newAdmin)
setName(newName)
saveInBackground {
if (it == null) {
Toasty.success(myContext, "Gespeichert").show()
showAnimation(true)
loadTechniker()
if (nameChanged) {
showAnimation(true)
loadMembers()
}
} else {
Toasty.error(myContext, "Fehler bei Speicherung").show()
Log.e("TechnikLogger.Techniker", it.message.toString())
@ -134,18 +133,18 @@ class ManageTechnikerFragment : Fragment() {
}
}
negativeButton(text = "Entlassen") {
val name = technikerNames[index]
val name = memberNames[index]
MaterialDialog(myContext).show {
title(text = "Entlassung")
message(text = "Soll '$name' wirklich entlassen werden?")
positiveButton(text = "Ja") {
techniker[index].apply {
put(COLUMN_TECHNIKER_ENTLASSEN, true)
members[index].apply {
retire()
saveInBackground {
if (it == null) {
Toasty.success(myContext, "Gespeichert").show()
showAnimation(true)
loadTechniker()
loadMembers()
} else {
Toasty.error(myContext, "Fehler bei Speicherung").show()
Log.e("TechnikLogger.Techniker", it.message.toString())

@ -17,9 +17,11 @@ import androidx.fragment.app.Fragment
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import com.cyb3rko.techniklogger.*
import com.cyb3rko.techniklogger.data.objects.Member
import com.cyb3rko.techniklogger.data.objects.Mission
import com.cyb3rko.techniklogger.data.ParseController
import com.cyb3rko.techniklogger.databinding.FragmentMissionBinding
import com.cyb3rko.techniklogger.data.Participation
import com.cyb3rko.techniklogger.data.objects.Participation
import com.cyb3rko.techniklogger.recycler.ParticipationAdapter
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.timepicker.MaterialTimePicker
@ -27,7 +29,6 @@ import com.google.android.material.timepicker.TimeFormat
import com.parse.ParseObject
import es.dmoral.toasty.Toasty
import java.sql.Time
import java.text.DecimalFormat
@SuppressLint("SetTextI18n")
class MissionFragment : Fragment() {
@ -35,10 +36,10 @@ class MissionFragment : Fragment() {
private lateinit var myContext: Context
private val args: MissionFragmentArgs by navArgs()
private lateinit var technikerAdapter: ParticipationAdapter
private lateinit var participationAdapter: ParticipationAdapter
private var adminMode = false
private var objectId = ""
private var dauer = ""
private var duration = 0f
private lateinit var sharedPref: SharedPreferences
private var time = ""
@ -58,9 +59,9 @@ class MissionFragment : Fragment() {
objectId = args.objectId
technikerAdapter = ParticipationAdapter {
participationAdapter = ParticipationAdapter {
if (adminMode || it.name == sharedPref.getString(NAME, "")) {
val uhrzeit = if (it.uhrzeit == "0") time else it.uhrzeit
val uhrzeit = if (it.time == "0") time else it.time
val message = "<strong><u>Arbeitszeit:</u></strong><br/>$uhrzeit Uhr<br/><br/>" +
"Wie möchtest du diesen Eintrag bearbeiten?"
@ -81,8 +82,8 @@ class MissionFragment : Fragment() {
var minute: String
var hoursInMillis: Long
var minutesInMillis: Long
if (it.uhrzeit != "0") {
val times = it.uhrzeit.split(" - ")
if (it.time != "0") {
val times = it.time.split(" - ")
builder.setHour(times[0].split(":")[0].toInt())
.setMinute(times[0].split(":")[1].toInt())
builder2.setHour(times[1].split(":")[0].toInt())
@ -127,32 +128,20 @@ class MissionFragment : Fragment() {
return@addOnPositiveButtonClickListener
}
tempTime += "${hour}:${minute}"
it.uhrzeit = tempTime
val tempDauer = DecimalFormat("#.#").format((time2.time - time1.time) / 3600 / 1000.toFloat())
it.dauer = tempDauer.replace(",", ".")
it.setTime(tempTime)
val tempDauer = (time2.time - time1.time) / 3600 / 1000.toFloat()
it.setDuration(tempDauer)
if (it.teilnahmeKey != "0") {
val dauerFloat = it.dauer.toFloat()
ParseObject.createWithoutData(CLASS_TEILNAHME, it.teilnahmeKey).apply {
put(COLUMN_EINSATZ_DAUER, dauerFloat)
put(COLUMN_EINSATZ_UHRZEIT, it.uhrzeit)
saveInBackground()
}
} else {
ParseController.fetchParticipation(objectId, it.objectId) { entry, e ->
if (e == null) {
it.teilnahmeKey = entry!!.objectId
val dauerFloat = it.dauer.toFloat()
ParseObject.createWithoutData(CLASS_TEILNAHME, it.teilnahmeKey).apply {
put(COLUMN_TEILNAHME_DAUER, dauerFloat)
put(COLUMN_TEILNAHME_UHRZEIT, it.uhrzeit)
saveInBackground {
loadData()
}
}
it.apply {
setDuration(duration)
setTime(it.time)
saveInBackground {
if (it == null) {
Toasty.success(myContext, "Arbeitszeit geändert").show()
loadParticipations()
} else {
Toasty.error(myContext, "Fehler bei Techniker-Abfrage").show()
Log.e("TechnikLogger.TechSuche", e.message.toString())
Toasty.error(myContext, "Fehler bei Speicherung").show()
Log.e("TechnikLogger.TechEdit", it.message.toString())
}
}
}
@ -160,31 +149,16 @@ class MissionFragment : Fragment() {
activity?.let { it1 -> picker.show(it1.supportFragmentManager, picker.tag) }
}
.setNegativeButton("Entfernen") { _, _ ->
val list = technikerAdapter.currentList.toMutableList()
val list = participationAdapter.currentList.toMutableList()
list.remove(it)
technikerAdapter.submitList(list)
participationAdapter.submitList(list)
updateTechnikerCount(list.size)
if (list.isEmpty()) {
showDivider(false)
}
if (it.teilnahmeKey != "0") {
ParseObject.createWithoutData(CLASS_TEILNAHME, it.teilnahmeKey).deleteInBackground()
} else {
ParseController.fetchParticipation(objectId, it.objectId) { entry, e ->
if (e == null) {
entry!!.deleteInBackground {
if (it != null) {
Toasty.error(myContext, "Fehler bei Techniker-Löschung").show()
Log.e("TechnikLogger.TechLösch", it.message.toString())
}
}
} else {
Toasty.error(myContext, "Fehler bei Techniker-Abfrage").show()
Log.e("TechnikLogger.TechSuche", e.message.toString())
}
}
}
if (technikerAdapter.currentList.size == 0) showDivider(false)
Participation.emptyObject(it.objectId).deleteInBackground()
if (participationAdapter.currentList.size == 0) showDivider(false)
loadParticipations()
}
.show()
}
@ -193,7 +167,7 @@ class MissionFragment : Fragment() {
loadData()
binding.recyclerView.layoutManager = LinearLayoutManager(myContext)
binding.recyclerView.adapter = technikerAdapter
binding.recyclerView.adapter = participationAdapter
binding.addButton.setOnClickListener {
val name = sharedPref.getString(NAME, "invalid")!!
@ -216,7 +190,7 @@ class MissionFragment : Fragment() {
ParseController.fetchParticipations(objectId, false) { entries, e ->
if (e == null) {
ParseObject.deleteAllInBackground(entries)
technikerAdapter.submitList(listOf())
participationAdapter.submitList(listOf())
showDivider(false)
updateTechnikerCount(0)
} else {
@ -249,44 +223,17 @@ class MissionFragment : Fragment() {
private fun loadData() {
ParseController.fetchMission(objectId) { mission, e ->
if (e == null) {
binding.titleView.text = mission!!.getString(COLUMN_EINSATZ_NAME)
binding.locationView.text = mission.getString(COLUMN_EINSATZ_ORT)
binding.titleView.text = mission!!.name
binding.locationView.text = mission.location
val dates = mission.getString(COLUMN_EINSATZ_DATUM)!!.split(",")
val dateParts = dates[0].split(".")
val date = "${dateParts[2]}.${dateParts[1]}.${dateParts[0]}"
dauer = mission.getNumber(COLUMN_EINSATZ_DAUER)!!.toString()
duration = mission.duration
if (dates.size > 1) time = dates[1]
val time = if (dates.size > 1) ", ${dates[1]}" else ", $dauer h"
val time = if (dates.size > 1) ", ${dates[1]}" else ", $duration h"
binding.dateView.text = date + time
ParseController.fetchParticipations(objectId, true) { entries, e2 ->
if (e2 == null) {
if (entries.isNotEmpty()) {
val techniker = mutableListOf<Participation>()
entries.forEach {
val teilnehmenderTechniker = it.getParseObject(COLUMN_TEILNAHME_VON)!!
val dauerEntry = it.getNumber(COLUMN_EINSATZ_DAUER)!!
val dauer = if (dauerEntry == 0) mission.getNumber(COLUMN_TEILNAHME_DAUER)!!.toString() else dauerEntry.toString()
val time = it.getString(COLUMN_EINSATZ_UHRZEIT)!!
techniker.add(
Participation(
dauer,
teilnehmenderTechniker.getString(COLUMN_EINSATZ_NAME)!!,
teilnehmenderTechniker.objectId,
it.objectId,
time
)
)
}
technikerAdapter.submitList(techniker)
updateTechnikerCount(techniker.size)
showDivider()
}
} else {
Toasty.error(myContext, "Fehler bei Teilnehmer-Abfrage").show()
Log.e("TechnikLogger.TechSuche", e2.message.toString())
}
}
loadParticipations()
} else {
if (e.message != null) {
if (e.message != "results not cached") {
@ -301,9 +248,28 @@ class MissionFragment : Fragment() {
}
}
private fun technikerExists(name: String): Boolean {
for (techniker in technikerAdapter.currentList) {
if (name == techniker.name) {
private fun loadParticipations() {
ParseController.fetchParticipations(objectId, true) { participations, e2 ->
if (e2 == null) {
if (participations.isNotEmpty()) {
participations.forEach {
if (it.duration == 0f) it.setDuration(duration)
}
participationAdapter.submitList(participations)
updateTechnikerCount(participations.size)
showDivider()
}
} else {
Toasty.error(myContext, "Fehler bei Teilnehmer-Abfrage").show()
Log.e("TechnikLogger.TechSuche", e2.message.toString())
}
}
}
private fun memberExists(name: String): Boolean {
for (member in participationAdapter.currentList) {
if (name == member.name) {
return true
}
}
@ -323,21 +289,17 @@ class MissionFragment : Fragment() {
}
private fun selfAdd(name: String, skip: Boolean = false) {
if (!technikerExists(name)) {
if (!memberExists(name)) {
if (!skip) {
MaterialAlertDialogBuilder(myContext)
.setMessage("Möchtest du dich als involvierter Techniker eintragen?")
.setPositiveButton("Ja") { _, _ ->
val technikerObject = ParseObject.createWithoutData(CLASS_TECHNIKER, sharedPref.getString(TECHNIKER_ID, "")!!)
technikerObject.put(COLUMN_TECHNIKER_NAME, sharedPref.getString(NAME, "")!!)
addTechniker(listOf(technikerObject))
addTechniker(listOf(sharedPref.getString(TECHNIKER_ID, "")!!))
}
.setNegativeButton("Abbrechen", null)
.show()
} else {
val technikerObject = ParseObject.createWithoutData(CLASS_TECHNIKER, sharedPref.getString(TECHNIKER_ID, "")!!)
technikerObject.put(COLUMN_TECHNIKER_NAME, sharedPref.getString(NAME, "")!!)
addTechniker(listOf(technikerObject))
addTechniker(listOf(sharedPref.getString(TECHNIKER_ID, "")!!))
}
} else {
MaterialAlertDialogBuilder(myContext)
@ -348,11 +310,11 @@ class MissionFragment : Fragment() {
}
private fun otherAdd() {
ParseController.fetchTechniker { techniker, names, e ->
ParseController.fetchMembers { members, memberNames, e ->
if (e == null) {
val currentSelection = BooleanArray(techniker.size)
names.forEachIndexed { index, name ->
technikerAdapter.currentList.forEach {
val currentSelection = BooleanArray(members.size)
memberNames.forEachIndexed { index, name ->
participationAdapter.currentList.forEach {
if (name == it.name) {
currentSelection[index] = true
}
@ -360,16 +322,16 @@ class MissionFragment : Fragment() {
}
val checkedNames = mutableListOf<String>()
val previousSelection = currentSelection.toList()
MaterialAlertDialogBuilder(myContext)
.setMultiChoiceItems(names.toTypedArray(), currentSelection) { dialogInterface, index, isChecked ->
val name = names[index]
.setMultiChoiceItems(memberNames.toTypedArray(), currentSelection) { dialogInterface, index, isChecked ->
println(memberNames[index])
val name = memberNames[index]
if (previousSelection[index]) {
var disabledIndex = -1
val listView = (dialogInterface as AlertDialog).listView
while (disabledIndex + 1 < names.size && (listView[disabledIndex + 1] as TextView).text != name) {
while (disabledIndex + 1 < memberNames.size && (listView[disabledIndex + 1] as TextView).text != name) {
disabledIndex++
}
if (disabledIndex != -1) (listView[disabledIndex + 1] as CheckedTextView).isChecked = true
@ -384,22 +346,15 @@ class MissionFragment : Fragment() {
}
}
.setPositiveButton("Hinzufügen") { _, _ ->
val newNameObjects = mutableListOf<ParseObject>()
techniker.forEach {
if (checkedNames.contains(it.getString(COLUMN_TECHNIKER_NAME)!!)) {
newNameObjects.add(it)
val newParticipationMemberIds = mutableListOf<String>()
members.forEach {
if (checkedNames.contains(it.name)) {
newParticipationMemberIds.add(it.objectId)
}
}
addTechniker(newNameObjects)
addTechniker(newParticipationMemberIds)
}
.create().apply {
setOnShowListener {
val dialogList = (it as AlertDialog).listView
currentSelection.forEachIndexed { index, b ->
if (b) dialogList[index].isEnabled = false
}
}
}.show()
.show()
} else {
Toasty.error(myContext, "Fehler bei Techniker-Suche").show()
Log.e("TechnikLogger.TechSuche", e.message.toString())
@ -407,16 +362,19 @@ class MissionFragment : Fragment() {
}
}
private fun addTechniker(newTechniker: List<ParseObject>) {
val project = ParseObject.createWithoutData(CLASS_EINSATZ, objectId)
val entryList = mutableListOf<ParseObject>()
newTechniker.forEach {
val entryObject = ParseObject(CLASS_TEILNAHME)
entryObject.put(COLUMN_TEILNAHME_VON, it)
entryObject.put(COLUMN_TEILNAHME_AN, project)
entryList.add(entryObject)
private fun addTechniker(memberIds: List<String>) {
val members = mutableListOf<Member>()
memberIds.forEach { members.add(Member.emptyObject(it)) }
val mission = Mission.emptyObject(objectId)
val newParticipations = mutableListOf<Participation>()
members.forEach {
Participation().apply {
put(Participation.COLUMN_BY, it)
put(Participation.COLUMN_IN, mission)
newParticipations.add(this)
}
}
ParseObject.saveAllInBackground(entryList) {
ParseObject.saveAllInBackground(newParticipations) {
if (it == null) {
loadData()
} else {
@ -435,7 +393,7 @@ class MissionFragment : Fragment() {
}
private fun emptyCheck() {
if (technikerAdapter.currentList.isEmpty()) {
if (participationAdapter.currentList.isEmpty()) {
binding.divider.visibility = View.GONE
}
}

@ -13,10 +13,9 @@ import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.cyb3rko.techniklogger.*
import com.cyb3rko.techniklogger.CLASS_EINSATZ
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_JAHR
import com.cyb3rko.techniklogger.CURRENT_YEAR
import com.cyb3rko.techniklogger.SHARED_PREFERENCE
import com.cyb3rko.techniklogger.data.objects.Mission
import com.cyb3rko.techniklogger.data.ParseController
import com.cyb3rko.techniklogger.databinding.FragmentMissionPusherBinding
import com.google.android.material.datepicker.MaterialDatePicker
@ -26,7 +25,6 @@ import com.google.android.material.timepicker.TimeFormat
import com.parse.ParseObject
import es.dmoral.toasty.Toasty
import java.sql.Time
import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.*
@ -37,11 +35,11 @@ class MissionPusherFragment : Fragment() {
private lateinit var childKey: String
private var date = ""
private lateinit var entry: ParseObject
private lateinit var mission: Mission
private var time = ""
private lateinit var time1: Time
private lateinit var time2: Time
private var duration = ""
private var duration = 0f
private lateinit var location: String
private lateinit var name: String
@SuppressLint("SimpleDateFormat")
@ -115,8 +113,9 @@ class MissionPusherFragment : Fragment() {
time2 = Time(hoursInMillis + minutesInMillis)
tempTime += "${hour}:${minute}"
time = tempTime
duration = DecimalFormat("#.#").format((time2.time - time1.time) / 3600 / 1000.toFloat())
duration = duration.replace(",", ".")
// duration = DecimalFormat("#.#").format((time2.time - time1.time) / 3600 / 1000.toFloat())
// duration = duration.replace(",", ".")
duration = (time2.time - time1.time) / 3600 / 1000.toFloat()
binding.durationView.text = Html.fromHtml("<b>Dauer:</b> $time Uhr, $duration Stunden")
}
activity?.let { it1 -> picker.show(it1.supportFragmentManager, picker.tag) }
@ -132,7 +131,7 @@ class MissionPusherFragment : Fragment() {
ParseController.fetchParticipations(childKey, false) { entries, e ->
if (e == null) {
ParseObject.deleteAllInBackground(entries) {
entry.deleteInBackground {
mission.deleteInBackground {
if (it == null) {
findNavController().navigate(R.id.navigation_listing)
} else {
@ -157,23 +156,19 @@ class MissionPusherFragment : Fragment() {
val location = binding.locationEditText.text.toString()
if (name != "" && location != "" && time != "") {
entry.put(COLUMN_EINSATZ_NAME, name)
entry.put(COLUMN_EINSATZ_ORT, location)
mission.setName(name)
mission.setLocation(location)
val dateTimes = date.split(".")
var dateTime = "${dateTimes[2]}.${dateTimes[1]}.${dateTimes[0]}"
if (time != "") dateTime += ",$time"
entry.put(COLUMN_EINSATZ_DATUM, dateTime)
entry.put(COLUMN_EINSATZ_DAUER, duration.toFloat())
mission.setDate(dateTime)
mission.setDuration(duration)
val sharedPref = context?.getSharedPreferences(
SHARED_PREFERENCE,
Context.MODE_PRIVATE
)
val jahrObject = ParseObject.createWithoutData(
CLASS_JAHR,
sharedPref?.getString(CURRENT_YEAR, "")!!
)
entry.put(COLUMN_EINSATZ_JAHR, jahrObject)
entry.saveInBackground {
mission.setYear(sharedPref?.getString(CURRENT_YEAR, "")!!)
mission.saveInBackground {
if (it == null) {
findNavController().navigate(R.id.navigation_listing)
} else {
@ -210,14 +205,14 @@ class MissionPusherFragment : Fragment() {
}
if (time != "") {
binding.durationView.text = Html.fromHtml("<b>Dauer:</b> $time Uhr, $duration Stunden")
} else if (duration != "") {
} else {
binding.durationView.text = Html.fromHtml("<b>Dauer:</b> $duration Stunden")
}
if (childKey == "") {
entry = ParseObject(CLASS_EINSATZ)
mission = Mission()
} else {
entry = ParseObject.createWithoutData(CLASS_EINSATZ, childKey)
mission = Mission.emptyObject(childKey)
}
}
}

@ -15,7 +15,7 @@ import com.cyb3rko.techniklogger.CURRENT_YEAR
import com.cyb3rko.techniklogger.CURRENT_YEAR_NAME
import com.cyb3rko.techniklogger.SHARED_PREFERENCE
import com.cyb3rko.techniklogger.data.ParseController
import com.cyb3rko.techniklogger.data.Year
import com.cyb3rko.techniklogger.data.objects.Year
import com.cyb3rko.techniklogger.databinding.FragmentYearsBinding
import com.cyb3rko.techniklogger.recycler.YearAdapter
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -28,7 +28,7 @@ class YearsFragment : Fragment() {
private var adminMode: Boolean? = null
private lateinit var yearAdapter: YearAdapter
private var data: MutableList<Year> = mutableListOf()
private var data: List<Year> = mutableListOf()
private lateinit var sharedPref: SharedPreferences
private lateinit var sharedPrefEditor: SharedPreferences.Editor
@ -99,13 +99,13 @@ class YearsFragment : Fragment() {
}
private fun loadEntries() {
ParseController.fetchYears { entries, e ->
ParseController.fetchYears { years, e ->
if (e == null) {
entries.forEach { data.add(Year(it.getString("name")!!, it.objectId)) }
data = years
showAnimation(false)
binding.swipeRefreshLayout.isRefreshing = false
yearAdapter.submitList(data)
(requireActivity() as MainActivity).setActionBarSubtitle(entries.size.toString())
yearAdapter.submitList(years)
(requireActivity() as MainActivity).setActionBarSubtitle(years.size.toString())
} else {
if (e.message != null) {
if (e.message != "results not cached") {

@ -9,11 +9,11 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.data.Mission
import com.cyb3rko.techniklogger.data.objects.Mission
import java.text.SimpleDateFormat
import java.util.*
class MissionAdapter(
internal class MissionAdapter(
val action: (objectId: String) -> Unit,
val actionLong: (mission: Mission) -> Boolean
) : ListAdapter<Mission, MissionAdapter.ViewHolder>(MissionDiffCallback) {
@ -29,14 +29,9 @@ class MissionAdapter(
val entry = currentList[position]
holder.textView.text = entry.name
holder.locationView.text = entry.location
if (entry.duration != "null") {
val date = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(entry.date)
@SuppressLint("SetTextI18n")
holder.dateView.text = "${date}, ${entry.duration} h"
} else {
val date = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(entry.date)
holder.dateView.text = date
}
val date = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(entry.date())
@SuppressLint("SetTextI18n")
holder.dateView.text = "${date}, ${entry.duration} h"
holder.itemView.setOnClickListener {
action(entry.objectId)
}
@ -59,10 +54,11 @@ class MissionAdapter(
}
override fun areContentsTheSame(oldItem: Mission, newItem: Mission): Boolean {
return oldItem.date == newItem.date &&
return oldItem.date() == newItem.date() &&
oldItem.duration == newItem.duration &&
oldItem.location == newItem.location &&
oldItem.name == newItem.name
oldItem.name == newItem.name &&
oldItem.time() == newItem.time()
}
}
}

@ -8,22 +8,20 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.data.Participation
import com.cyb3rko.techniklogger.data.objects.Participation
class ParticipationAdapter(
val action: (techniker: Participation) -> Unit
internal class ParticipationAdapter(
val action: (participation: Participation) -> Unit
) : ListAdapter<Participation, ParticipationAdapter.ViewHolder>(ParticipationDiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_recycler_techniker, parent, false)
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_member, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val entry = getItem(position)
val title = "${entry.name}, ${entry.dauer} h"
val title = "${entry.name}, ${entry.duration} h"
holder.titleView.text = title
holder.titleView.setOnClickListener {
action(entry)
@ -40,10 +38,9 @@ class ParticipationAdapter(
}
override fun areContentsTheSame(oldItem: Participation, newItem: Participation): Boolean {
return oldItem.dauer == newItem.dauer &&
return oldItem.duration == newItem.duration &&
oldItem.name == newItem.name &&
oldItem.teilnahmeKey == newItem.teilnahmeKey &&
oldItem.uhrzeit == newItem.uhrzeit
oldItem.time == newItem.time
}
}
}

@ -9,9 +9,9 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.data.Year
import com.cyb3rko.techniklogger.data.objects.Year
class YearAdapter(
internal class YearAdapter(
val action: (year: Year) -> Unit
) : ListAdapter<Year, YearAdapter.ViewHolder>(YearDiffCallback) {

@ -8,7 +8,8 @@ import android.view.View
import androidx.core.content.FileProvider
import com.cyb3rko.techniklogger.data.ParseController
import com.cyb3rko.techniklogger.databinding.FragmentListingBinding
import com.cyb3rko.techniklogger.data.Mission
import com.cyb3rko.techniklogger.data.objects.Mission
import com.cyb3rko.techniklogger.toPrettyString
import com.itextpdf.text.*
import com.itextpdf.text.pdf.PdfPTable
import com.itextpdf.text.pdf.PdfWriter
@ -21,7 +22,7 @@ import java.text.SimpleDateFormat
import java.util.*
import kotlin.Exception
class ExportBuilder(
internal class ExportBuilder(
private val myContext: Context,
data: MutableList<Mission>,
private val binding: FragmentListingBinding,
@ -98,10 +99,10 @@ class ExportBuilder(
private fun export() {
data.forEachIndexed { index, mission ->
val information = listOf(
SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(mission.date),
SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(mission.date()),
mission.name,
techniker[index].joinToString("\n"),
mission.duration)
mission.duration.toPrettyString())
information.forEachIndexed { _, string ->
table.addCell(NormalCell(string))
}

@ -14,7 +14,7 @@
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/item_recycler_techniker"/>
tools:listitem="@layout/item_member"/>
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/loading_animation"

@ -51,8 +51,8 @@
android:defaultValue="" />
<argument
android:name="duration"
app:argType="string"
android:defaultValue="" />
app:argType="float"
android:defaultValue="0" />
<argument
android:name="location"
app:argType="string"
@ -73,8 +73,8 @@
<fragment
android:id="@+id/navigation_manage_techniker"
android:name="com.cyb3rko.techniklogger.fragments.ManageTechnikerFragment"
android:name="com.cyb3rko.techniklogger.fragments.ManageMembersFragment"
android:label="Techniker verwalten"
tools:layout="@layout/fragment_manage_techniker" />
tools:layout="@layout/fragment_manage_members" />
</navigation>
Loading…
Cancel
Save