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 package com.cyb3rko.techniklogger
import android.app.Application 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.Parse
import com.parse.ParseObject
class App : Application() { class App : Application() {
override fun onCreate() { override fun onCreate() {
super.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) if (BuildConfig.DEBUG) Parse.setLogLevel(Parse.LOG_LEVEL_DEBUG) else Parse.setLogLevel(Parse.LOG_LEVEL_NONE)
Parse.initialize(Parse.Configuration.Builder(this) Parse.initialize(Parse.Configuration.Builder(this)
.applicationId("technik-logger") .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.TextInputEditText
import com.google.android.material.textfield.TextInputLayout 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_ADMIN = "admin"
internal const val COLUMN_TECHNIKER_ENTLASSEN = "entlassen"
internal const val COLUMN_TECHNIKER_NAME = "name" internal const val COLUMN_TECHNIKER_NAME = "name"
internal const val CURRENT_YEAR = "current_year" internal const val CURRENT_YEAR = "current_year"
internal const val CURRENT_YEAR_NAME = "current_year_name" 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 package com.cyb3rko.techniklogger.data
import com.cyb3rko.techniklogger.* import com.cyb3rko.techniklogger.data.objects.Member
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_DATUM import com.cyb3rko.techniklogger.data.objects.Mission
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_DAUER import com.cyb3rko.techniklogger.data.objects.Participation
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_JAHR import com.cyb3rko.techniklogger.data.objects.Year
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_NAME
import com.cyb3rko.techniklogger.COLUMN_EINSATZ_ORT
import com.parse.ParseException import com.parse.ParseException
import com.parse.ParseObject import com.parse.ParseObject
import com.parse.ParseQuery import com.parse.ParseQuery
import java.text.SimpleDateFormat
import java.util.*
object ParseController { object ParseController {
private fun <T : ParseObject>getQuery( private inline fun <reified T : ParseObject>getQuery(
className: String,
allowCache: Boolean = true allowCache: Boolean = true
): ParseQuery<T> { ): ParseQuery<T> {
return ParseQuery<T>(className).apply { return ParseQuery(T::class.java).apply {
limit = -1 limit = -1
cachePolicy = if (allowCache) { cachePolicy = if (allowCache) {
ParseQuery.CachePolicy.CACHE_THEN_NETWORK ParseQuery.CachePolicy.CACHE_THEN_NETWORK
} else ParseQuery.CachePolicy.NETWORK_ONLY } else {
ParseQuery.CachePolicy.NETWORK_ONLY
}
} }
} }
internal fun fetchAdminStatus( internal fun fetchAdminStatus(
userName: String?, name: String?,
action: (objectId: String?, admin: Boolean?, e: ParseException?) -> Unit action: (objectId: String?, admin: Boolean?, e: ParseException?) -> Unit
) { ) {
val query = getQuery<ParseObject>("Techniker", false) val query = getQuery<Member>(false)
query.whereEqualTo("name", userName) query.whereEqualTo(Member.COLUMN_NAME, name)
query.getFirstInBackground { techniker, e -> query.getFirstInBackground { member, e ->
if (e == null) { if (e == null) {
action(techniker.objectId, techniker.getBoolean("admin"), e) action(member.objectId, member.admin, e)
} else { } else {
action(null, null, e) action(null, null, e)
} }
} }
} }
internal fun fetchYears(action: (entries: List<ParseObject>, e: ParseException?) -> Unit) { internal fun fetchYears(action: (entries: List<Year>, e: ParseException?) -> Unit) {
val query = getQuery<ParseObject>("Jahr") val query = getQuery<Year>()
query.orderByDescending(COLUMN_JAHR_NAME) query.orderByDescending(Year.COLUMN_NAME)
query.findInBackground { entries, e -> query.findInBackground { years, e ->
if (e == null) { if (e == null) {
action(entries, null) action(years, null)
} else action(listOf(), e) } else action(listOf(), e)
} }
} }
internal fun fetchMission( internal fun fetchMission(
objectId: String?, objectId: String?,
action: (entry: ParseObject?, e: ParseException?) -> Unit action: (mission: Mission?, e: ParseException?) -> Unit
) { ) {
val query = getQuery<ParseObject>(CLASS_EINSATZ) val query = getQuery<Mission>()
query.getInBackground(objectId) { entry, e -> query.getInBackground(objectId) { mission, e ->
if (e == null) { if (e == null) {
action(entry, null) action(mission, null)
} else { } else {
action(null, e) action(null, e)
} }
@ -66,89 +63,56 @@ object ParseController {
} }
internal fun fetchMissions( internal fun fetchMissions(
year: String?, year: String,
action: (missions: List<Mission>, e: ParseException?) -> Unit action: (missions: List<Mission>, e: ParseException?) -> Unit
) { ) {
val query = getQuery<ParseObject>("Einsatz") val query = getQuery<Mission>()
query.orderByDescending(COLUMN_EINSATZ_DATUM) query.orderByDescending(Mission.COLUMN_DATE)
query.whereEqualTo( query.whereEqualTo(Mission.COLUMN_YEAR, Year.emptyObject(year))
COLUMN_EINSATZ_JAHR, query.findInBackground { missions, e ->
ParseObject.createWithoutData(
"Jahr",
year
)
)
query.findInBackground { objects, e ->
if (e == null) { if (e == null) {
val data = mutableListOf<Mission>() action(missions, null)
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)
} else { } else {
action(listOf(), e) 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( internal fun fetchParticipations(
missionId: String, missionId: String,
includeTechniker: Boolean, includeMember: Boolean,
action: (entries: List<ParseObject>, e: ParseException?) -> Unit action: (participations: List<Participation>, e: ParseException?) -> Unit
) { ) {
val query = getQuery<ParseObject>(CLASS_TEILNAHME, false) val query = getQuery<Participation>(false)
query.whereEqualTo("an", ParseObject.createWithoutData(CLASS_EINSATZ, missionId)) query.whereEqualTo(Participation.COLUMN_IN, Mission.emptyObject(missionId))
if (includeTechniker) query.include("von") if (includeMember) query.include(Participation.COLUMN_BY)
query.findInBackground { entries, e -> query.findInBackground { participations, e ->
if (e == null) { if (e == null) {
action(entries, null) if (includeMember) participations.sortBy { it.name }
} else action(listOf(), e) action(participations, null)
} else {
action(listOf(), e)
}
} }
} }
internal fun fetchTechniker( internal fun fetchMembers(
action: ( action: (
techniker: List<ParseObject>, members: List<Member>,
technikerNames: List<String>, memberNames: List<String>,
e: ParseException? e: ParseException?
) -> Unit ) -> Unit
) { ) {
val query = getQuery<ParseObject>(CLASS_TECHNIKER, false) val query = getQuery<Member>(false)
query.whereEqualTo(COLUMN_TECHNIKER_ENTLASSEN, false) query.whereEqualTo(Member.COLUMN_RETIRED, false)
query.orderByAscending(COLUMN_TECHNIKER_NAME) query.orderByAscending(Member.COLUMN_NAME)
query.findInBackground { objects, e -> query.findInBackground { members, e ->
if (e == null) { if (e == null) {
val techniker = mutableListOf<String>() val names = mutableListOf<String>()
objects.forEach { members.forEach {
techniker.add(it.getString(COLUMN_TECHNIKER_NAME)!!) names.add(it.name)
} }
action(objects, techniker, null) action(members, names, null)
} else { } else {
action(listOf(), listOf(), e) 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 lateinit var myContext: Context
private var adminMode: Boolean? = null private var adminMode: Boolean? = null
private lateinit var projectsAdapter: MissionAdapter private lateinit var missionAdapter: MissionAdapter
private var isFABOpen = false private var isFABOpen = false
private lateinit var sharedPref: SharedPreferences private lateinit var sharedPref: SharedPreferences
private lateinit var sharedPrefEditor: SharedPreferences.Editor private lateinit var sharedPrefEditor: SharedPreferences.Editor
@ -51,18 +51,18 @@ class ListingFragment : Fragment() {
binding.loadingAnimation.playAnimation() binding.loadingAnimation.playAnimation()
projectsAdapter = MissionAdapter({ objectId: String -> missionAdapter = MissionAdapter({ objectId: String ->
val action = ListingFragmentDirections.navigateToProject(objectId) val action = ListingFragmentDirections.navigateToProject(objectId)
findNavController().navigate(action) findNavController().navigate(action)
}, { }, {
if (adminMode != null && adminMode!!) { if (adminMode != null && adminMode!!) {
val action = ListingFragmentDirections.navigateToPusher( 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, duration = it.duration,
location = it.location, location = it.location,
name = it.name, name = it.name,
objectId = it.objectId, objectId = it.objectId,
time = it.time time = it.time()
) )
findNavController().navigate(action) findNavController().navigate(action)
true true
@ -71,7 +71,7 @@ class ListingFragment : Fragment() {
binding.recyclerView.apply { binding.recyclerView.apply {
layoutManager = LinearLayoutManager(myContext) layoutManager = LinearLayoutManager(myContext)
adapter = projectsAdapter adapter = missionAdapter
} }
loadEntries() loadEntries()
@ -97,7 +97,7 @@ class ListingFragment : Fragment() {
closeFABMenu() closeFABMenu()
ExportBuilder( ExportBuilder(
myContext, myContext,
projectsAdapter.currentList, missionAdapter.currentList,
binding, binding,
sharedPref.getString("current_year_name", "")!! sharedPref.getString("current_year_name", "")!!
) )
@ -138,21 +138,19 @@ class ListingFragment : Fragment() {
if (empty) { if (empty) {
null null
} else { } else {
projectsAdapter.currentList.size.toString() missionAdapter.currentList.size.toString()
} }
) )
} }
private fun loadEntries() { private fun loadEntries() {
ParseController.fetchMissions( ParseController.fetchMissions(sharedPref.getString(CURRENT_YEAR, "")!!) { missions, e ->
sharedPref.getString(CURRENT_YEAR, "")
) { entries, e ->
if (e == null) { if (e == null) {
showAnimation(false) showAnimation(false)
binding.swipeRefreshLayout.isRefreshing = 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) { override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
super.onItemRangeInserted(positionStart, itemCount) super.onItemRangeInserted(positionStart, itemCount)
binding.recyclerView.smoothScrollToPosition(0) binding.recyclerView.smoothScrollToPosition(0)
@ -162,7 +160,7 @@ class ListingFragment : Fragment() {
if (e.message != null) { if (e.message != null) {
if (e.message != "results not cached") { if (e.message != "results not cached") {
binding.swipeRefreshLayout.isRefreshing = false binding.swipeRefreshLayout.isRefreshing = false
if (projectsAdapter.currentList.isEmpty()) { if (missionAdapter.currentList.isEmpty()) {
showAnimation(true, false) showAnimation(true, false)
} }
Toasty.error(myContext, "Abruf fehlgeschlagen", Toasty.LENGTH_SHORT).show() 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.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.callbacks.onDismiss import com.afollestad.materialdialogs.callbacks.onDismiss
import com.afollestad.materialdialogs.customview.customView import com.afollestad.materialdialogs.customview.customView
import com.androidnetworking.AndroidNetworking.put import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.* import com.cyb3rko.techniklogger.data.objects.Member
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.data.ParseController 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.switchmaterial.SwitchMaterial
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import com.parse.ParseObject
import es.dmoral.toasty.Toasty import es.dmoral.toasty.Toasty
class ManageTechnikerFragment : Fragment() { class ManageMembersFragment : Fragment() {
private var _binding: FragmentManageTechnikerBinding? = null private var _binding: FragmentManageMembersBinding? = null
private lateinit var myContext: Context private lateinit var myContext: Context
private val technikerNames = mutableListOf<String>() private val memberNames = mutableListOf<String>()
private val binding get() = _binding!! private val binding get() = _binding!!
@ -39,28 +34,29 @@ class ManageTechnikerFragment : Fragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
_binding = FragmentManageTechnikerBinding.inflate(inflater, container, false) _binding = FragmentManageMembersBinding.inflate(inflater, container, false)
val root = binding.root val root = binding.root
myContext = requireContext() myContext = requireContext()
loadTechniker() loadMembers()
binding.fab.setOnClickListener { binding.fab.setOnClickListener {
MaterialDialog(myContext, BottomSheet(LayoutMode.WRAP_CONTENT)).show { MaterialDialog(myContext, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(text = "Techniker hinzufügen") title(text = "Techniker hinzufügen")
customView(R.layout.techniker_dialog, horizontalPadding = true) customView(R.layout.member_dialog, horizontalPadding = true)
positiveButton(text = "Hinzufügen") { positiveButton(text = "Hinzufügen") {
val view = it.view val view = it.view
val newName = view.findViewById<TextInputEditText>(R.id.name).text.toString() val newName = view.findViewById<TextInputEditText>(R.id.name).text.toString()
val newAdmin = view.findViewById<SwitchMaterial>(R.id.admin).isChecked val newAdmin = view.findViewById<SwitchMaterial>(R.id.admin).isChecked
ParseObject.create(CLASS_TECHNIKER).apply {
put(COLUMN_TECHNIKER_NAME, newName) Member().apply {
put(COLUMN_TECHNIKER_ADMIN, newAdmin) setAdmin(newAdmin)
setName(newName)
saveInBackground { saveInBackground {
if (it == null) { if (it == null) {
Toasty.success(myContext, "Hinzugefügt").show() Toasty.success(myContext, "Hinzugefügt").show()
showAnimation(true) showAnimation(true)
loadTechniker() loadMembers()
} else { } else {
Toasty.error(myContext, "Fehler bei Speicherung").show() Toasty.error(myContext, "Fehler bei Speicherung").show()
Log.e("TechnikLogger.Techniker", it.message.toString()) Log.e("TechnikLogger.Techniker", it.message.toString())
@ -77,35 +73,35 @@ class ManageTechnikerFragment : Fragment() {
setOnRefreshListener { setOnRefreshListener {
isRefreshing = false isRefreshing = false
showAnimation(true) showAnimation(true)
loadTechniker() loadMembers()
} }
} }
return root return root
} }
private fun loadTechniker() { private fun loadMembers() {
technikerNames.clear() memberNames.clear()
binding.list.adapter = ArrayAdapter( binding.list.adapter = ArrayAdapter(
myContext, myContext,
android.R.layout.simple_list_item_1, android.R.layout.simple_list_item_1,
technikerNames memberNames
) )
ParseController.fetchTechniker { techniker, technikerNames, e -> ParseController.fetchMembers { members, memberNames, e ->
if (e == null) { if (e == null) {
val adapter = ArrayAdapter( val adapter = ArrayAdapter(
myContext, myContext,
android.R.layout.simple_list_item_1, android.R.layout.simple_list_item_1,
technikerNames memberNames
) )
binding.list.adapter = adapter binding.list.adapter = adapter
showAnimation(false) showAnimation(false)
binding.list.setOnItemClickListener { _, _, index, _ -> binding.list.setOnItemClickListener { _, _, index, _ ->
val dialogView = layoutInflater.inflate(R.layout.techniker_dialog, null) val dialogView = layoutInflater.inflate(R.layout.member_dialog, null)
dialogView.findViewById<TextInputEditText>(R.id.name).setText(technikerNames[index]) dialogView.findViewById<TextInputEditText>(R.id.name).setText(memberNames[index])
dialogView.findViewById<SwitchMaterial>(R.id.admin).isChecked = techniker[index].getBoolean(COLUMN_TECHNIKER_ADMIN) dialogView.findViewById<SwitchMaterial>(R.id.admin).isChecked = members[index].admin
MaterialDialog(myContext, BottomSheet(LayoutMode.WRAP_CONTENT)).show { MaterialDialog(myContext, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(text = "Techniker-Info") title(text = "Techniker-Info")
customView(0, dialogView, horizontalPadding = true) customView(0, dialogView, horizontalPadding = true)
@ -113,18 +109,21 @@ class ManageTechnikerFragment : Fragment() {
val view = it.view val view = it.view
val newName = view.findViewById<TextInputEditText>(R.id.name).text.toString() val newName = view.findViewById<TextInputEditText>(R.id.name).text.toString()
val newAdmin = view.findViewById<SwitchMaterial>(R.id.admin).isChecked val newAdmin = view.findViewById<SwitchMaterial>(R.id.admin).isChecked
val parseObject = techniker[index] val member = members[index]
if (newName != parseObject.getString(COLUMN_TECHNIKER_NAME) ||
newAdmin != parseObject.getBoolean(COLUMN_TECHNIKER_ADMIN) val adminChanged = newAdmin != member.admin
) { val nameChanged = newName != member.name
parseObject.apply { if (adminChanged || nameChanged) {
put(COLUMN_TECHNIKER_NAME, newName) member.apply {
put(COLUMN_TECHNIKER_ADMIN, newAdmin) setAdmin(newAdmin)
setName(newName)
saveInBackground { saveInBackground {
if (it == null) { if (it == null) {
Toasty.success(myContext, "Gespeichert").show() Toasty.success(myContext, "Gespeichert").show()
showAnimation(true) if (nameChanged) {
loadTechniker() showAnimation(true)
loadMembers()
}
} else { } else {
Toasty.error(myContext, "Fehler bei Speicherung").show() Toasty.error(myContext, "Fehler bei Speicherung").show()
Log.e("TechnikLogger.Techniker", it.message.toString()) Log.e("TechnikLogger.Techniker", it.message.toString())
@ -134,18 +133,18 @@ class ManageTechnikerFragment : Fragment() {
} }
} }
negativeButton(text = "Entlassen") { negativeButton(text = "Entlassen") {
val name = technikerNames[index] val name = memberNames[index]
MaterialDialog(myContext).show { MaterialDialog(myContext).show {
title(text = "Entlassung") title(text = "Entlassung")
message(text = "Soll '$name' wirklich entlassen werden?") message(text = "Soll '$name' wirklich entlassen werden?")
positiveButton(text = "Ja") { positiveButton(text = "Ja") {
techniker[index].apply { members[index].apply {
put(COLUMN_TECHNIKER_ENTLASSEN, true) retire()
saveInBackground { saveInBackground {
if (it == null) { if (it == null) {
Toasty.success(myContext, "Gespeichert").show() Toasty.success(myContext, "Gespeichert").show()
showAnimation(true) showAnimation(true)
loadTechniker() loadMembers()
} else { } else {
Toasty.error(myContext, "Fehler bei Speicherung").show() Toasty.error(myContext, "Fehler bei Speicherung").show()
Log.e("TechnikLogger.Techniker", it.message.toString()) Log.e("TechnikLogger.Techniker", it.message.toString())

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

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

@ -9,11 +9,11 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.cyb3rko.techniklogger.R import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.data.Mission import com.cyb3rko.techniklogger.data.objects.Mission
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
class MissionAdapter( internal class MissionAdapter(
val action: (objectId: String) -> Unit, val action: (objectId: String) -> Unit,
val actionLong: (mission: Mission) -> Boolean val actionLong: (mission: Mission) -> Boolean
) : ListAdapter<Mission, MissionAdapter.ViewHolder>(MissionDiffCallback) { ) : ListAdapter<Mission, MissionAdapter.ViewHolder>(MissionDiffCallback) {
@ -29,14 +29,9 @@ class MissionAdapter(
val entry = currentList[position] val entry = currentList[position]
holder.textView.text = entry.name holder.textView.text = entry.name
holder.locationView.text = entry.location holder.locationView.text = entry.location
if (entry.duration != "null") { val date = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(entry.date())
val date = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(entry.date) @SuppressLint("SetTextI18n")
@SuppressLint("SetTextI18n") holder.dateView.text = "${date}, ${entry.duration} h"
holder.dateView.text = "${date}, ${entry.duration} h"
} else {
val date = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(entry.date)
holder.dateView.text = date
}
holder.itemView.setOnClickListener { holder.itemView.setOnClickListener {
action(entry.objectId) action(entry.objectId)
} }
@ -59,10 +54,11 @@ class MissionAdapter(
} }
override fun areContentsTheSame(oldItem: Mission, newItem: Mission): Boolean { override fun areContentsTheSame(oldItem: Mission, newItem: Mission): Boolean {
return oldItem.date == newItem.date && return oldItem.date() == newItem.date() &&
oldItem.duration == newItem.duration && oldItem.duration == newItem.duration &&
oldItem.location == newItem.location && 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.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.cyb3rko.techniklogger.R import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.data.Participation import com.cyb3rko.techniklogger.data.objects.Participation
class ParticipationAdapter( internal class ParticipationAdapter(
val action: (techniker: Participation) -> Unit val action: (participation: Participation) -> Unit
) : ListAdapter<Participation, ParticipationAdapter.ViewHolder>(ParticipationDiffCallback) { ) : ListAdapter<Participation, ParticipationAdapter.ViewHolder>(ParticipationDiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context) val view = LayoutInflater.from(parent.context).inflate(R.layout.item_member, parent, false)
.inflate(R.layout.item_recycler_techniker, parent, false)
return ViewHolder(view) return ViewHolder(view)
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val entry = getItem(position) val entry = getItem(position)
val title = "${entry.name}, ${entry.dauer} h" val title = "${entry.name}, ${entry.duration} h"
holder.titleView.text = title holder.titleView.text = title
holder.titleView.setOnClickListener { holder.titleView.setOnClickListener {
action(entry) action(entry)
@ -40,10 +38,9 @@ class ParticipationAdapter(
} }
override fun areContentsTheSame(oldItem: Participation, newItem: Participation): Boolean { override fun areContentsTheSame(oldItem: Participation, newItem: Participation): Boolean {
return oldItem.dauer == newItem.dauer && return oldItem.duration == newItem.duration &&
oldItem.name == newItem.name && oldItem.name == newItem.name &&
oldItem.teilnahmeKey == newItem.teilnahmeKey && oldItem.time == newItem.time
oldItem.uhrzeit == newItem.uhrzeit
} }
} }
} }

@ -9,9 +9,9 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.cyb3rko.techniklogger.R 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 val action: (year: Year) -> Unit
) : ListAdapter<Year, YearAdapter.ViewHolder>(YearDiffCallback) { ) : ListAdapter<Year, YearAdapter.ViewHolder>(YearDiffCallback) {

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

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

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