Ändere von Multi-Activity zu Multi-Fragment

master
Niko Diamadis 5 years ago
parent 5516980e0c
commit 96cac7a560

@ -4,6 +4,7 @@ apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.mikepenz.aboutlibraries.plugin' apply plugin: 'com.mikepenz.aboutlibraries.plugin'
apply plugin: "androidx.navigation.safeargs.kotlin"
android { android {
signingConfigs { signingConfigs {
@ -50,6 +51,9 @@ android {
kotlinOptions { kotlinOptions {
jvmTarget = '1.8' jvmTarget = '1.8'
} }
buildFeatures {
viewBinding true
}
packagingOptions { packagingOptions {
pickFirst'META-INF/library_release.kotlin_module' pickFirst'META-INF/library_release.kotlin_module'
} }
@ -60,6 +64,9 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.core:core-ktx:1.3.2'
implementation "androidx.multidex:multidex:2.0.1"
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.4'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.4'
implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.afollestad.material-dialogs:input:3.3.0' implementation 'com.afollestad.material-dialogs:input:3.3.0'
implementation 'com.airbnb.android:lottie:3.4.2' implementation 'com.airbnb.android:lottie:3.4.2'

@ -24,14 +24,10 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.cyb3rko.techniklogger.ProjectActivity"
android:screenOrientation="portrait" />
<activity android:name="com.cyb3rko.techniklogger.utils.About" <activity android:name="com.cyb3rko.techniklogger.utils.About"
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />
<activity android:name="com.cyb3rko.techniklogger.utils.IconCredits" <activity android:name="com.cyb3rko.techniklogger.utils.IconCredits"
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />
<activity android:name="com.cyb3rko.techniklogger.EinsatzPusher"
android:screenOrientation="portrait" />
<activity android:name="com.mikepenz.aboutlibraries.ui.LibsActivity" <activity android:name="com.mikepenz.aboutlibraries.ui.LibsActivity"
android:theme="@style/NoActionBar" android:theme="@style/NoActionBar"
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />

@ -7,39 +7,46 @@ import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.input.getInputField import com.afollestad.materialdialogs.input.getInputField
import com.afollestad.materialdialogs.input.input import com.afollestad.materialdialogs.input.input
import com.androidnetworking.AndroidNetworking import com.androidnetworking.AndroidNetworking
import com.androidnetworking.error.ANError import com.androidnetworking.error.ANError
import com.androidnetworking.interfaces.StringRequestListener import com.androidnetworking.interfaces.StringRequestListener
import com.cyb3rko.techniklogger.recycler.ProjectEntryViewHolder import com.cyb3rko.techniklogger.databinding.ActivityMainBinding
import com.cyb3rko.techniklogger.recycler.ProjectViewState import com.cyb3rko.techniklogger.databinding.FragmentListingBinding
import com.cyb3rko.techniklogger.fragments.EinsatzPusherFragment
import com.cyb3rko.techniklogger.utils.About import com.cyb3rko.techniklogger.utils.About
import com.parse.ParseObject import com.parse.ParseObject
import com.parse.ParseQuery import com.parse.ParseQuery
import es.dmoral.toasty.Toasty import es.dmoral.toasty.Toasty
import kotlinx.android.synthetic.main.activity_main.*
import me.ibrahimyilmaz.kiel.adapter.RecyclerViewAdapter
import me.ibrahimyilmaz.kiel.adapter.RecyclerViewAdapter.Companion.adapterOf
import me.ibrahimyilmaz.kiel.core.RecyclerViewHolder
import java.text.SimpleDateFormat
import java.util.* import java.util.*
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private var _binding: ActivityMainBinding? = null
private var adminMode = false
private val data: MutableList<ProjectViewState.ProjectEntry> = mutableListOf()
private lateinit var sharedPref: SharedPreferences private lateinit var sharedPref: SharedPreferences
private lateinit var sharedPrefEditor: SharedPreferences.Editor private lateinit var sharedPrefEditor: SharedPreferences.Editor
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) // This property is only valid between onCreateView and onDestroyView.
_binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val navController = findNavController(R.id.nav_host_fragment_activity_main)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(setOf(R.id.navigation_listing))
setupActionBarWithNavController(navController, appBarConfiguration)
sharedPref = getSharedPreferences("Safe", 0) sharedPref = getSharedPreferences("Safe", 0)
sharedPrefEditor = sharedPref.edit() sharedPrefEditor = sharedPref.edit()
@ -47,56 +54,8 @@ class MainActivity : AppCompatActivity() {
if (sharedPref.getString("name", "") == "") { if (sharedPref.getString("name", "") == "") {
showNameDialog() showNameDialog()
} else {
updateAdminStatus()
} }
loading_animation.playAnimation()
val adapter = adapterOf<ProjectViewState> {
register(
layoutResource = R.layout.item_recycler_projects,
viewHolder = ::ProjectEntryViewHolder,
onBindBindViewHolder = { vh, _, text ->
vh.textView.text = text.text
vh.locationView.text = text.location
if (text.duration != "null") {
vh.dateView.text = "${SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(text.date)}, ${text.duration} h"
} else {
vh.dateView.text = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(text.date)
}
vh.itemView.setOnClickListener {
ProjectActivityBuilder(applicationContext)
.setKey(text.childKey)
.start()
}
vh.itemView.setOnLongClickListener {
if (adminMode) {
val intent = Intent(applicationContext, EinsatzPusher::class.java)
intent.putExtra("childKey", text.childKey)
intent.putExtra("name", text.text)
intent.putExtra("location", text.location)
intent.putExtra("date", SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(text.date))
intent.putExtra("time", text.time)
intent.putExtra("duration", text.duration)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
true
} else false
}
}
)
}
adapter.submitList(data as List<ProjectViewState>?)
val linearLayoutManager = LinearLayoutManager(applicationContext)
linearLayoutManager.reverseLayout = true
linearLayoutManager.stackFromEnd = true
recycler_view.layoutManager = linearLayoutManager
recycler_view.adapter = adapter
loadEntries(adapter)
updateCheck() updateCheck()
} }
@ -116,82 +75,12 @@ class MainActivity : AppCompatActivity() {
} }
positiveButton(0, "Speichern") { positiveButton(0, "Speichern") {
sharedPref.edit().putString("name", inputName.toString()).apply() sharedPref.edit().putString("name", inputName.toString()).commit()
updateAdminStatus()
}
}
}
}
private fun loadEntries(adapter: RecyclerViewAdapter<ProjectViewState, RecyclerViewHolder<ProjectViewState>>) {
val query = ParseQuery.getQuery<ParseObject>("Einsatz")
query.limit = 100000
query.findInBackground { objects, e ->
if (e == null) {
objects.forEach {
val dates = it["datum"].toString().split(",")
val time = if (dates.size > 1) dates[1] else ""
data.add(data.size, ProjectViewState.ProjectEntry(
it.objectId,
it["name"].toString(),
it["ort"].toString(),
SimpleDateFormat("yyyy.MM.dd", Locale.GERMANY).parse(dates[0])!!,
time,
it["dauer"].toString()
))
}
data.sortBy { it.date }
hideProgress()
adapter.notifyDataSetChanged()
recycler_view.scheduleLayoutAnimation()
recycler_view.scrollBy(0, -10000)
} else {
Toasty.error(applicationContext, "Abruf fehlgeschlagen", Toasty.LENGTH_SHORT).show()
Log.e("TechnikLogger.EinsSuche", e.message.toString())
}
}
}
private fun hideProgress() {
loading_animation.visibility = View.GONE
loading_animation.cancelAnimation()
}
private fun updateAdminStatus() {
val query = ParseQuery.getQuery<ParseObject>("Techniker")
query.whereEqualTo("name", sharedPref.getString("name", ""))
query.getFirstInBackground { techniker, e ->
if (e == null) {
if (techniker.getBoolean("admin")) {
adminMode = true
sharedPrefEditor.putBoolean("admin", adminMode)
sharedPrefEditor.putString("technikerId", techniker.objectId).apply()
floatingActionButton.show()
floatingActionButton.setOnClickListener {
startActivity(Intent(applicationContext, EinsatzPusher::class.java))
finish() finish()
startActivity(Intent(applicationContext, MainActivity::class.java))
} }
} else {
adminMode = false
sharedPrefEditor.putBoolean("admin", adminMode).apply()
floatingActionButton.hide()
} }
} else {
floatingActionButton.hide()
adminMode = false
sharedPrefEditor.putBoolean("admin", adminMode).apply()
Toasty.error(applicationContext, "Adminstatus unbekannt", Toasty.LENGTH_SHORT).show()
Log.e("TechnikLogger.TechSuche", e.message.toString())
} }
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
} }
private fun updateCheck() { private fun updateCheck() {
@ -211,13 +100,23 @@ class MainActivity : AppCompatActivity() {
}) })
} }
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_activity_main)
return navController.navigateUp() || super.onSupportNavigateUp()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will // Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long // automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml. // as you specify a parent activity in AndroidManifest.xml.
when (item.itemId) { when (item.itemId) {
R.id.action_rename -> showNameDialog() R.id.action_rename -> showNameDialog()
R.id.action_admin -> updateAdminStatus()
R.id.action_about -> startActivity(Intent(applicationContext, About::class.java)) R.id.action_about -> startActivity(Intent(applicationContext, About::class.java))
// R.id.action_privacy_policy -> // R.id.action_privacy_policy ->
// R.id.action_terms_of_use -> // R.id.action_terms_of_use ->

@ -1,21 +0,0 @@
package com.cyb3rko.techniklogger
import android.content.Context
import android.content.Intent
class ProjectActivityBuilder(private val context: Context) {
private var childKey = ""
fun setKey(childKey: String): ProjectActivityBuilder {
this.childKey = childKey
return this
}
fun start() {
val intent = Intent(context, ProjectActivity::class.java)
intent.putExtra("childKey", childKey)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intent)
}
}

@ -1,26 +1,33 @@
package com.cyb3rko.techniklogger package com.cyb3rko.techniklogger.fragments
import android.annotation.SuppressLint import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.Html import android.text.Html
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.view.MenuItem import android.util.Log
import android.view.LayoutInflater
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatActivity import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.databinding.FragmentEinsatzPusherBinding
import com.google.android.material.datepicker.MaterialDatePicker import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.timepicker.MaterialTimePicker import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat 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 kotlinx.android.synthetic.main.activity_einsatz_pusher.*
import java.sql.Time import java.sql.Time
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
class EinsatzPusher : AppCompatActivity() { class EinsatzPusherFragment : Fragment() {
private var _binding: FragmentEinsatzPusherBinding? = null
private lateinit var myContext: Context
private val args: EinsatzPusherFragmentArgs by navArgs()
private lateinit var childKey: String private lateinit var childKey: String
private var date = "" private var date = ""
@ -31,28 +38,29 @@ class EinsatzPusher : AppCompatActivity() {
private var duration = "" private var duration = ""
private lateinit var location: String private lateinit var location: String
private lateinit var name: String private lateinit var name: String
private val simpleDateFormat = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY) private val simpleDateFormat = SimpleDateFormat("dd.MM.yyyy")
@SuppressLint("SetTextI18n") // This property is only valid between onCreateView and onDestroyView.
override fun onCreate(savedInstanceState: Bundle?) { private val binding get() = _binding!!
getBundleInformation()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_einsatz_pusher)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = FragmentEinsatzPusherBinding.inflate(inflater, container, false)
val root = binding.root
myContext = requireContext()
getArgumentInformation()
restoreInformation() restoreInformation()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
val builder = MaterialDatePicker.Builder.datePicker().setTitleText("Datum") val builder = MaterialDatePicker.Builder.datePicker().setTitleText("Datum")
val builder2 = MaterialTimePicker.Builder().setTimeFormat(TimeFormat.CLOCK_24H).setTitleText("Von") val builder2 = MaterialTimePicker.Builder().setTimeFormat(TimeFormat.CLOCK_24H).setTitleText("Von")
val builder3 = MaterialTimePicker.Builder().setTimeFormat(TimeFormat.CLOCK_24H).setTitleText("Bis") val builder3 = MaterialTimePicker.Builder().setTimeFormat(TimeFormat.CLOCK_24H).setTitleText("Bis")
date_button.setOnClickListener { binding.dateButton.setOnClickListener {
if (date != "null") { if (date != "") {
val dateInMillis = simpleDateFormat.parse(date)!!.time val dateInMillis = simpleDateFormat.parse(date)!!.time
builder.setSelection(dateInMillis + 3600000) builder.setSelection(dateInMillis + 7200000)
} }
if (time != "null") { if (time != "") {
val times = time.split(" - ") val times = time.split(" - ")
builder2.setHour(times[0].split(":")[0].toInt()) builder2.setHour(times[0].split(":")[0].toInt())
.setMinute(times[0].split(":")[1].toInt()) .setMinute(times[0].split(":")[1].toInt())
@ -69,8 +77,8 @@ class EinsatzPusher : AppCompatActivity() {
var minutesInMillis: Long var minutesInMillis: Long
picker.addOnPositiveButtonClickListener { picker.addOnPositiveButtonClickListener {
date = simpleDateFormat.format(Date(it)) date = simpleDateFormat.format(Date(it))
date_view.text = Html.fromHtml("<b>Datum:</b><br/>${date}") binding.dateView.text = Html.fromHtml("<b>Datum:</b><br/>${date}")
picker2.show(supportFragmentManager, picker2.tag) activity?.let { it1 -> picker2.show(it1.supportFragmentManager, picker2.tag) }
} }
picker2.addOnPositiveButtonClickListener { picker2.addOnPositiveButtonClickListener {
hour = picker2.hour.toString() hour = picker2.hour.toString()
@ -81,7 +89,7 @@ class EinsatzPusher : AppCompatActivity() {
minutesInMillis = picker2.minute.toLong() * 60000 minutesInMillis = picker2.minute.toLong() * 60000
time1 = Time(hoursInMillis + minutesInMillis) time1 = Time(hoursInMillis + minutesInMillis)
tempTime += "${hour}:${minute} - " tempTime += "${hour}:${minute} - "
picker3.show(supportFragmentManager, picker3.tag) activity?.let { it1 -> picker3.show(it1.supportFragmentManager, picker3.tag) }
} }
picker3.addOnPositiveButtonClickListener { picker3.addOnPositiveButtonClickListener {
hour = picker3.hour.toString() hour = picker3.hour.toString()
@ -95,30 +103,38 @@ class EinsatzPusher : AppCompatActivity() {
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_view.text = Html.fromHtml("<b>Dauer:</b> $time Uhr, $duration Stunden") binding.durationView.text = Html.fromHtml("<b>Dauer:</b> $time Uhr, $duration Stunden")
} }
picker.show(supportFragmentManager, picker.tag) activity?.let { it1 -> picker.show(it1.supportFragmentManager, picker.tag) }
} }
if (childKey != "null") { if (childKey != "") {
delete_button.visibility = View.VISIBLE binding.deleteButton.visibility = View.VISIBLE
delete_button.setOnClickListener { binding.deleteButton.setOnClickListener {
MaterialDialog(this) MaterialDialog(myContext)
.show { .show {
message(0, "Möchtest du diesen Einsatz entfernen?") message(0, "Möchtest du diesen Einsatz entfernen?")
positiveButton(0, "Ja") { positiveButton(0, "Ja") {
entry.deleteInBackground() entry.deleteInBackground {
if (it == null) {
findNavController().navigate(R.id.navigation_listing)
} else {
Toasty.error(myContext, "Fehler bei Löschung").show()
Log.e("TechnikLogger.Einsätze", it.message.toString())
}
}
} }
negativeButton(0, "Abbrechen") negativeButton(0, "Abbrechen")
} }
} }
} }
finished_button.setOnClickListener { binding.finishedButton.setOnClickListener {
val name = nameEditText.text.toString() val name = binding.nameEditText.text.toString()
val location = locationEditText.text.toString() val location = binding.locationEditText.text.toString()
if (name != "" && location != "" && time != "null") { if (name != "" && location != "" && time != "") {
entry.put("name", name) entry.put("name", name)
entry.put("ort", location) entry.put("ort", location)
val dateTimes = date.split(".") val dateTimes = date.split(".")
@ -126,66 +142,54 @@ class EinsatzPusher : AppCompatActivity() {
if (time != "") dateTime += ",$time" if (time != "") dateTime += ",$time"
entry.put("datum", dateTime) entry.put("datum", dateTime)
entry.put("dauer", duration.toFloat()) entry.put("dauer", duration.toFloat())
if (childKey == "null") { if (childKey == "") {
entry.put("techniker", listOf<String>()) entry.put("techniker", listOf<String>())
} }
entry.saveInBackground() entry.saveInBackground() {
finish() if (it == null) {
startActivity(Intent(applicationContext, MainActivity::class.java)) findNavController().navigate(R.id.navigation_listing)
} else {
Toasty.error(myContext, "Fehler bei Speicherung").show()
Log.e("TechnikLogger.Einsätze", it.message.toString())
}
}
} else { } else {
Toasty.error(applicationContext, "Fülle zuerst alle Felder aus").show() Toasty.error(myContext, "Fülle zuerst alle Felder aus").show()
} }
} }
return root
} }
private fun getBundleInformation() { private fun getArgumentInformation() {
childKey = intent.extras?.getString("childKey").toString() childKey = args.childKey
name = intent.extras?.getString("name").toString() name = args.name
location = intent.extras?.getString("location").toString() location = args.location
date = intent.extras?.getString("date").toString() date = args.date
time = intent.extras?.getString("time").toString() time = args.time
duration = intent.extras?.getString("duration").toString() duration = args.duration
} }
private fun restoreInformation() { private fun restoreInformation() {
if (name != "null") { if (name != "") {
nameEditText.text = SpannableStringBuilder(name) binding.nameEditText.text = SpannableStringBuilder(name)
} }
if (location != "null") { if (location != "") {
locationEditText.text = SpannableStringBuilder(location) binding.locationEditText.text = SpannableStringBuilder(location)
} }
if (date != "null") { if (date != "") {
date_view.text = Html.fromHtml("<b>Datum:</b><br/>${date}") binding.dateView.text = Html.fromHtml("<b>Datum:</b><br/>${date}")
} }
if (time != "null") { if (time != "") {
duration_view.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 != "null") { } else if (duration != "") {
duration_view.text = Html.fromHtml("<b>Dauer:</b> $duration Stunden") binding.durationView.text = Html.fromHtml("<b>Dauer:</b> $duration Stunden")
} }
if (childKey == "null") { if (childKey == "") {
entry = ParseObject("Einsatz") entry = ParseObject("Einsatz")
} else { } else {
entry = ParseObject.createWithoutData("Einsatz", childKey) entry = ParseObject.createWithoutData("Einsatz", childKey)
} }
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
when (item.itemId) {
android.R.id.home -> {
finish()
startActivity(Intent(applicationContext, MainActivity::class.java))
}
}
return super.onOptionsItemSelected(item)
}
override fun onBackPressed() {
finish()
startActivity(Intent(applicationContext, MainActivity::class.java))
}
} }

@ -0,0 +1,165 @@
package com.cyb3rko.techniklogger.fragments
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.databinding.FragmentListingBinding
import com.cyb3rko.techniklogger.recycler.ProjectEntryViewHolder
import com.cyb3rko.techniklogger.recycler.ProjectViewState
import com.parse.ParseObject
import com.parse.ParseQuery
import es.dmoral.toasty.Toasty
import me.ibrahimyilmaz.kiel.adapter.RecyclerViewAdapter
import me.ibrahimyilmaz.kiel.core.RecyclerViewHolder
import java.text.SimpleDateFormat
import java.util.*
class ListingFragment : Fragment() {
private var _binding: FragmentListingBinding? = null
private lateinit var myContext: Context
private var adminMode = false
private val data: MutableList<ProjectViewState.ProjectEntry> = mutableListOf()
private lateinit var sharedPref: SharedPreferences
private lateinit var sharedPrefEditor: SharedPreferences.Editor
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentListingBinding.inflate(inflater, container, false)
val root = binding.root
myContext = requireContext()
sharedPref = myContext.getSharedPreferences("Safe", 0)
sharedPrefEditor = sharedPref.edit()
sharedPrefEditor.apply()
binding.loadingAnimation.playAnimation()
val adapter = RecyclerViewAdapter.adapterOf<ProjectViewState> {
register(
layoutResource = R.layout.item_recycler_projects,
viewHolder = ::ProjectEntryViewHolder,
onBindBindViewHolder = { vh, _, text ->
vh.textView.text = text.text
vh.locationView.text = text.location
if (text.duration != "null") {
vh.dateView.text = "${SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(text.date)}, ${text.duration} h"
} else {
vh.dateView.text = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(text.date)
}
vh.itemView.setOnClickListener {
val action = ListingFragmentDirections.navigateToProject(childKey = text.childKey)
findNavController().navigate(action)
}
vh.itemView.setOnLongClickListener {
if (adminMode) {
val action = ListingFragmentDirections.navigateToPusher(
childKey = text.childKey,
name = text.text,
location = text.location,
date = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY).format(text.date),
time = text.time,
duration = text.duration
)
findNavController().navigate(action)
true
} else false
}
}
)
}
adapter.submitList(data as List<ProjectViewState>?)
val linearLayoutManager = LinearLayoutManager(myContext)
linearLayoutManager.reverseLayout = true
linearLayoutManager.stackFromEnd = true
binding.recyclerView.layoutManager = linearLayoutManager
binding.recyclerView.adapter = adapter
loadEntries(adapter)
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
updateAdminStatus()
}
private fun loadEntries(adapter: RecyclerViewAdapter<ProjectViewState, RecyclerViewHolder<ProjectViewState>>) {
data.clear()
val query = ParseQuery.getQuery<ParseObject>("Einsatz")
query.limit = 100000
query.findInBackground { objects, e ->
if (e == null) {
objects.forEach {
val dates = it["datum"].toString().split(",")
val time = if (dates.size > 1) dates[1] else ""
data.add(data.size, ProjectViewState.ProjectEntry(
it.objectId,
it["name"].toString(),
it["ort"].toString(),
SimpleDateFormat("yyyy.MM.dd", Locale.GERMANY).parse(dates[0])!!,
time,
it["dauer"].toString()
))
}
data.sortBy { it.date }
hideProgress()
adapter.notifyDataSetChanged()
binding.recyclerView.scheduleLayoutAnimation()
binding.recyclerView.scrollBy(0, -10000)
} else {
Toasty.error(myContext, "Abruf fehlgeschlagen", Toasty.LENGTH_SHORT).show()
Log.e("TechnikLogger.EinsSuche", e.message.toString())
}
}
}
private fun hideProgress() {
binding.loadingAnimation.visibility = View.GONE
binding.loadingAnimation.cancelAnimation()
}
private fun updateAdminStatus() {
val query = ParseQuery.getQuery<ParseObject>("Techniker")
query.whereEqualTo("name", sharedPref.getString("name", ""))
query.getFirstInBackground { techniker, e ->
if (e == null) {
if (techniker.getBoolean("admin")) {
adminMode = true
sharedPrefEditor.putBoolean("admin", adminMode)
sharedPrefEditor.putString("technikerId", techniker.objectId).apply()
binding.floatingActionButton.show()
binding.floatingActionButton.setOnClickListener {
val action = ListingFragmentDirections.navigateToPusher()
findNavController().navigate(action)
}
} else {
adminMode = false
sharedPrefEditor.putBoolean("admin", adminMode).apply()
binding.floatingActionButton.hide()
}
} else {
binding.floatingActionButton.hide()
adminMode = false
sharedPrefEditor.putBoolean("admin", adminMode).apply()
Toasty.error(myContext, "Adminstatus unbekannt", Toasty.LENGTH_SHORT).show()
Log.e("TechnikLogger.TechSuche", e.message.toString())
}
}
}
}

@ -1,13 +1,13 @@
package com.cyb3rko.techniklogger package com.cyb3rko.techniklogger.fragments
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.Menu import android.view.*
import android.view.MenuItem import androidx.fragment.app.Fragment
import android.view.View import androidx.navigation.fragment.navArgs
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.input.getInputField import com.afollestad.materialdialogs.input.getInputField
@ -15,21 +15,23 @@ import com.afollestad.materialdialogs.input.input
import com.afollestad.materialdialogs.list.isItemChecked import com.afollestad.materialdialogs.list.isItemChecked
import com.afollestad.materialdialogs.list.listItemsMultiChoice import com.afollestad.materialdialogs.list.listItemsMultiChoice
import com.afollestad.materialdialogs.list.uncheckItems import com.afollestad.materialdialogs.list.uncheckItems
import com.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.databinding.FragmentProjectBinding
import com.cyb3rko.techniklogger.recycler.ProjectTechnikerViewHolder import com.cyb3rko.techniklogger.recycler.ProjectTechnikerViewHolder
import com.cyb3rko.techniklogger.recycler.ProjectTechnikerViewState import com.cyb3rko.techniklogger.recycler.ProjectTechnikerViewState
import com.parse.ParseObject import com.parse.ParseObject
import com.parse.ParseQuery import com.parse.ParseQuery
import es.dmoral.toasty.Toasty import es.dmoral.toasty.Toasty
import kotlinx.android.synthetic.main.activity_main.*
import java.lang.IndexOutOfBoundsException import java.lang.IndexOutOfBoundsException
import me.ibrahimyilmaz.kiel.adapter.RecyclerViewAdapter.Companion.adapterOf import me.ibrahimyilmaz.kiel.adapter.RecyclerViewAdapter.Companion.adapterOf
import kotlinx.android.synthetic.main.activity_project.*
import kotlinx.android.synthetic.main.activity_project.recycler_view
import me.ibrahimyilmaz.kiel.adapter.RecyclerViewAdapter import me.ibrahimyilmaz.kiel.adapter.RecyclerViewAdapter
import me.ibrahimyilmaz.kiel.core.RecyclerViewHolder import me.ibrahimyilmaz.kiel.core.RecyclerViewHolder
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
class ProjectActivity : AppCompatActivity() { class ProjectFragment : Fragment() {
private var _binding: FragmentProjectBinding? = null
private lateinit var myContext: Context
private val args: ProjectFragmentArgs by navArgs()
private lateinit var adapter: RecyclerViewAdapter<ProjectTechnikerViewState, RecyclerViewHolder<ProjectTechnikerViewState>> private lateinit var adapter: RecyclerViewAdapter<ProjectTechnikerViewState, RecyclerViewHolder<ProjectTechnikerViewState>>
private var adminMode = false private var adminMode = false
@ -38,16 +40,19 @@ class ProjectActivity : AppCompatActivity() {
private lateinit var sharedPref: SharedPreferences private lateinit var sharedPref: SharedPreferences
private val techniker: MutableList<ProjectTechnikerViewState.ProjectTechniker> = mutableListOf() private val techniker: MutableList<ProjectTechnikerViewState.ProjectTechniker> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) { private val binding get() = _binding!!
childKey = intent.extras?.getString("childKey").toString()
einsatz = ParseObject.createWithoutData("Einsatz", childKey)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_project)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
sharedPref = getSharedPreferences("Safe", 0) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentProjectBinding.inflate(inflater, container, false)
val root = binding.root
myContext = requireContext()
sharedPref = myContext.getSharedPreferences("Safe", 0)
adminMode = sharedPref.getBoolean("admin", false) adminMode = sharedPref.getBoolean("admin", false)
childKey = args.childKey
einsatz = ParseObject.createWithoutData("Einsatz", childKey)
adapter = adapterOf { adapter = adapterOf {
register( register(
layoutResource = R.layout.item_recycler_techniker, layoutResource = R.layout.item_recycler_techniker,
@ -56,7 +61,7 @@ class ProjectActivity : AppCompatActivity() {
vh.textView.text = text.name vh.textView.text = text.name
vh.itemView.setOnClickListener { vh.itemView.setOnClickListener {
if (adminMode) { if (adminMode) {
MaterialDialog(this@ProjectActivity) MaterialDialog(myContext)
.show { .show {
message(text = "Möchtest du \'${text.name}\' entfernen?") message(text = "Möchtest du \'${text.name}\' entfernen?")
positiveButton(text = "Ja") { positiveButton(text = "Ja") {
@ -64,8 +69,8 @@ class ProjectActivity : AppCompatActivity() {
einsatz.put("techniker", techniker) einsatz.put("techniker", techniker)
einsatz.saveInBackground() einsatz.saveInBackground()
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
this@ProjectActivity.recycler_view.scheduleLayoutAnimation() binding.recyclerView.scheduleLayoutAnimation()
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}" binding.technikerView.text = "Techniker: ${techniker.size}"
if (techniker.size == 0) showDivider(false) if (techniker.size == 0) showDivider(false)
} }
negativeButton(text = "Abbrechen") negativeButton(text = "Abbrechen")
@ -96,35 +101,35 @@ class ProjectActivity : AppCompatActivity() {
techniker.add(ProjectTechnikerViewState.ProjectTechniker(it.getString("name")!!, it.objectId)) techniker.add(ProjectTechnikerViewState.ProjectTechniker(it.getString("name")!!, it.objectId))
} }
techniker.sortBy { it.name } techniker.sortBy { it.name }
recycler_view.scheduleLayoutAnimation() binding.recyclerView.scheduleLayoutAnimation()
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
techniker_view.text = "Techniker: ${techniker.size}" binding.technikerView.text = "Techniker: ${techniker.size}"
showDivider() showDivider()
} else { } else {
Toasty.error(applicationContext, "Fehler bei Id-Abfrage", Toasty.LENGTH_SHORT).show() Toasty.error(myContext, "Fehler bei Id-Abfrage", Toasty.LENGTH_SHORT).show()
Log.e("TechnikLogger.TechSuche", e2.message.toString()) Log.e("TechnikLogger.TechSuche", e2.message.toString())
} }
} }
} }
title_view.text = einsatz["name"].toString() binding.titleView.text = einsatz["name"].toString()
location_view.text = einsatz["ort"].toString() binding.locationView.text = einsatz["ort"].toString()
val dates = einsatz["datum"].toString().split(",") val dates = einsatz["datum"].toString().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]}"
val time = if (dates.size > 1) ", ${dates[1]}" else "" val time = if (dates.size > 1) ", ${dates[1]}" else ""
date_view.text = date + time binding.dateView.text = date + time
} else { } else {
Toasty.error(applicationContext, "Abruf fehlgeschlagen", Toasty.LENGTH_SHORT).show() Toasty.error(myContext, "Abruf fehlgeschlagen", Toasty.LENGTH_SHORT).show()
Log.e("TechnikLogger.TechSuche", e.message.toString()) Log.e("TechnikLogger.TechSuche", e.message.toString())
} }
} }
adapter.submitList(techniker as List<ProjectTechnikerViewState>?) adapter.submitList(techniker as List<ProjectTechnikerViewState>?)
recycler_view.layoutManager = LinearLayoutManager(applicationContext) binding.recyclerView.layoutManager = LinearLayoutManager(myContext)
recycler_view.adapter = adapter binding.recyclerView.adapter = adapter
add_button.setOnClickListener { binding.addButton.setOnClickListener {
val name = sharedPref.getString("name", "invalid")!! val name = sharedPref.getString("name", "invalid")!!
if (!adminMode) selfAdd(name) else bothAdd(name) if (!adminMode) selfAdd(name) else bothAdd(name)
} }
@ -132,9 +137,9 @@ class ProjectActivity : AppCompatActivity() {
emptyCheck() emptyCheck()
if (adminMode) { if (adminMode) {
reset_button.visibility = View.VISIBLE binding.resetButton.visibility = View.VISIBLE
reset_button.setOnClickListener { binding.resetButton.setOnClickListener {
MaterialDialog(this).show { MaterialDialog(myContext).show {
message(text = "Möchtest du alle eingetragenen Techniker entfernen?") message(text = "Möchtest du alle eingetragenen Techniker entfernen?")
positiveButton(text = "Ja") { positiveButton(text = "Ja") {
einsatz.put("techniker", listOf<String>()) einsatz.put("techniker", listOf<String>())
@ -142,12 +147,14 @@ class ProjectActivity : AppCompatActivity() {
techniker.clear() techniker.clear()
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
showDivider(false) showDivider(false)
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}" binding.technikerView.text = "Techniker: ${techniker.size}"
} }
negativeButton(text = "Abbrechen") negativeButton(text = "Abbrechen")
} }
} }
} }
return root
} }
private fun technikerExists(name: String): Boolean { private fun technikerExists(name: String): Boolean {
@ -160,7 +167,7 @@ class ProjectActivity : AppCompatActivity() {
} }
private fun bothAdd(name: String) { private fun bothAdd(name: String) {
MaterialDialog(this) MaterialDialog(myContext)
.show { .show {
message(text = "Möchtest du nur dich oder auch andere Techniker eintragen?") message(text = "Möchtest du nur dich oder auch andere Techniker eintragen?")
positiveButton(text = "Mich") { positiveButton(text = "Mich") {
@ -175,7 +182,7 @@ class ProjectActivity : AppCompatActivity() {
private fun selfAdd(name: String, skip: Boolean = false) { private fun selfAdd(name: String, skip: Boolean = false) {
if (!technikerExists(name)) { if (!technikerExists(name)) {
if (!skip) { if (!skip) {
MaterialDialog(this).show { MaterialDialog(myContext).show {
message(text = "Möchtest du dich als involvierter Techniker eintragen?") message(text = "Möchtest du dich als involvierter Techniker eintragen?")
positiveButton(text = "Ja") { positiveButton(text = "Ja") {
val entry = ParseObject.createWithoutData("Einsatz", childKey) val entry = ParseObject.createWithoutData("Einsatz", childKey)
@ -185,8 +192,8 @@ class ProjectActivity : AppCompatActivity() {
techniker.sortBy { it.name } techniker.sortBy { it.name }
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
showDivider(true) showDivider(true)
this@ProjectActivity.recycler_view.scheduleLayoutAnimation() binding.recyclerView.scheduleLayoutAnimation()
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}" binding.technikerView.text = "Techniker: ${techniker.size}"
} }
negativeButton(text = "Abbrechen") negativeButton(text = "Abbrechen")
} }
@ -198,11 +205,11 @@ class ProjectActivity : AppCompatActivity() {
techniker.sortBy { it.name } techniker.sortBy { it.name }
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
showDivider(true) showDivider(true)
this@ProjectActivity.recycler_view.scheduleLayoutAnimation() binding.recyclerView.scheduleLayoutAnimation()
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}" binding.technikerView.text = "Techniker: ${techniker.size}"
} }
} else { } else {
MaterialDialog(this) MaterialDialog(myContext)
.show { .show {
message(text = "Du bist bereits eingetragen.") message(text = "Du bist bereits eingetragen.")
positiveButton(text = "Ok") positiveButton(text = "Ok")
@ -231,7 +238,7 @@ class ProjectActivity : AppCompatActivity() {
} }
} }
val intArray = currentSelection.toIntArray() val intArray = currentSelection.toIntArray()
MaterialDialog(this@ProjectActivity).show { MaterialDialog(myContext).show {
listItemsMultiChoice(items = names, initialSelection = intArray, disabledIndices = intArray) listItemsMultiChoice(items = names, initialSelection = intArray, disabledIndices = intArray)
positiveButton(text = "Hinzufügen") { positiveButton(text = "Hinzufügen") {
it.uncheckItems(intArray) it.uncheckItems(intArray)
@ -248,34 +255,34 @@ class ProjectActivity : AppCompatActivity() {
techniker.sortBy { it.name } techniker.sortBy { it.name }
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
showDivider(true) showDivider(true)
this@ProjectActivity.recycler_view.scheduleLayoutAnimation() binding.recyclerView.scheduleLayoutAnimation()
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}" binding.technikerView.text = "Techniker: ${techniker.size}"
} }
negativeButton(text = "Abbrechen") { negativeButton(text = "Abbrechen") {
addTechniker.clear() addTechniker.clear()
} }
} }
} else { } else {
Toasty.error(applicationContext, "Fehler bei Id-Abfrage", Toasty.LENGTH_SHORT).show() Toasty.error(myContext, "Fehler bei Id-Abfrage", Toasty.LENGTH_SHORT).show()
Log.e("TechnikLogger.TechSuche", e.message.toString()) Log.e("TechnikLogger.TechSuche", e.message.toString())
} }
} }
} }
private fun showDivider(show: Boolean = true) { private fun showDivider(show: Boolean = true) {
divider.visibility = if (show) View.VISIBLE else View.GONE binding.divider.visibility = if (show) View.VISIBLE else View.GONE
} }
private fun emptyCheck() { private fun emptyCheck() {
if (techniker.isEmpty()) { if (techniker.isEmpty()) {
divider.visibility = View.GONE binding.divider.visibility = View.GONE
} }
} }
private fun showNameDialog() { private fun showNameDialog() {
val currentName = getSharedPreferences("Safe", 0).getString("name", "") val currentName = myContext.getSharedPreferences("Safe", 0).getString("name", "")
MaterialDialog(this) MaterialDialog(myContext)
.cancelable(false) .cancelable(false)
.title(0, "Bitte gebe deinen Namen ein") .title(0, "Bitte gebe deinen Namen ein")
.show { .show {
@ -288,32 +295,10 @@ class ProjectActivity : AppCompatActivity() {
} }
positiveButton { positiveButton {
getSharedPreferences("Safe", 0).edit().putString("name", inputName.toString()).apply() myContext.getSharedPreferences("Safe", 0).edit().putString("name", inputName.toString()).apply()
} }
} }
positiveButton(0, "Speichern") positiveButton(0, "Speichern")
} }
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
when (item.itemId) {
android.R.id.home -> finish()
R.id.action_rename -> showNameDialog()
// R.id.action_icons -> setContentView(AboutIcons(applicationContext, R.drawable::class.java).setTitle("Benutzte Icons").get())
// R.id.action_libraries -> LibsBuilder().start(this)
// R.id.action_privacy_policy ->
// R.id.action_terms_of_use ->
}
return super.onOptionsItemSelected(item)
}
} }

@ -1,59 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:orientation="vertical"
tools:context=".MainActivity">
<TextView <fragment
android:id="@+id/title" android:id="@+id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent" app:defaultNavHost="true"
app:layout_constraintStart_toStartOf="parent" app:navGraph="@navigation/mobile_navigation" />
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="12dp"
android:gravity="center_horizontal"
android:text="Einsätze"
android:textSize="26sp"
android:textStyle="bold"
android:fontFamily="sans-serif-black"
tools:ignore="HardcodedText" />
<com.airbnb.lottie.LottieAnimationView </RelativeLayout>
android:id="@+id/loading_animation"
android:layout_width="150dp"
android:layout_height="150dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/recycler_view"
android:layout_marginTop="30dp"
app:lottie_fileName="loading.json"
app:lottie_loop="true"
app:lottie_speed="1.5"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="12dp"
android:layoutAnimation="@anim/recycler_animation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:src="@drawable/_icon_add"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -80,7 +81,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Datum:\n---" android:text="Datum:\n---"
android:textAlignment="center" android:textAlignment="center"
android:layout_gravity="center_vertical" android:layout_gravity="center"
android:foregroundGravity="center_vertical" android:foregroundGravity="center_vertical"
android:layout_marginStart="20dp" android:layout_marginStart="20dp"
android:textSize="16sp"/> android:textSize="16sp"/>
@ -123,7 +124,7 @@
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:textAlignment="center" android:textAlignment="center"
android:layout_gravity="center_vertical" android:layout_gravity="center"
android:foregroundGravity="center_vertical" android:foregroundGravity="center_vertical"
android:layout_marginStart="20dp" android:layout_marginStart="20dp"
android:textSize="16sp"/> android:textSize="16sp"/>
@ -155,6 +156,7 @@
android:visibility="gone" android:visibility="gone"
style="@style/Widget.MaterialComponents.Button" style="@style/Widget.MaterialComponents.Button"
android:textSize="12sp" android:textSize="12sp"
android:text="Einsatz entfernen" /> android:text="Einsatz entfernen"
tools:visibility="visible" />
</LinearLayout> </LinearLayout>

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="12dp"
android:gravity="center_horizontal"
android:text="Einsätze"
android:textSize="26sp"
android:textStyle="bold"
android:fontFamily="sans-serif-black"
tools:ignore="HardcodedText" />
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/loading_animation"
android:layout_width="150dp"
android:layout_height="150dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/recycler_view"
android:layout_marginTop="30dp"
app:lottie_fileName="loading.json"
app:lottie_loop="true"
app:lottie_speed="1.5"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="12dp"
android:layoutAnimation="@anim/recycler_animation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:src="@drawable/_icon_add"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -7,11 +7,6 @@
android:title="Namen ändern" android:title="Namen ändern"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_admin"
android:title="Adminstatus abrufen"
app:showAsAction="never" />
<item <item
android:id="@+id/action_about" android:id="@+id/action_about"
android:title="Über" android:title="Über"

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mobile_navigation"
app:startDestination="@+id/navigation_listing">
<fragment
android:id="@+id/navigation_listing"
android:name="com.cyb3rko.techniklogger.fragments.ListingFragment"
android:label="Einsätze"
tools:layout="@layout/fragment_listing">
<action
android:id="@+id/navigateToProject"
app:destination="@id/navigation_project" />
<action
android:id="@+id/navigateToPusher"
app:destination="@id/navigation_einsatz_pusher" />
</fragment>
<fragment
android:id="@+id/navigation_project"
android:name="com.cyb3rko.techniklogger.fragments.ProjectFragment"
android:label="Einsatz"
tools:layout="@layout/fragment_project" >
<argument
android:name="childKey"
app:argType="string"
android:defaultValue="" />
<action
android:id="@+id/navigateToListing"
app:destination="@id/navigation_listing" />
</fragment>
<fragment
android:id="@+id/navigation_einsatz_pusher"
android:name="com.cyb3rko.techniklogger.fragments.EinsatzPusherFragment"
android:label="Einsatz bearbeiten"
tools:layout="@layout/fragment_einsatz_pusher">
<action
android:id="@+id/navigateToListing"
app:destination="@id/navigation_listing" />
<argument
android:name="childKey"
app:argType="string"
android:defaultValue="" />
<argument
android:name="name"
app:argType="string"
android:defaultValue=""/>
<argument
android:name="location"
app:argType="string"
android:defaultValue=""/>
<argument
android:name="date"
app:argType="string"
android:defaultValue=""/>
<argument
android:name="time"
app:argType="string"
android:defaultValue=""/>
<argument
android:name="duration"
app:argType="string"
android:defaultValue=""/>
</fragment>
</navigation>

@ -12,6 +12,7 @@ buildscript {
classpath 'com.google.gms:google-services:4.3.4' classpath 'com.google.gms:google-services:4.3.4'
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries_version" classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.4"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

Loading…
Cancel
Save