Ä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.gms.google-services'
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
apply plugin: "androidx.navigation.safeargs.kotlin"
android {
signingConfigs {
@ -50,6 +51,9 @@ android {
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
viewBinding true
}
packagingOptions {
pickFirst'META-INF/library_release.kotlin_module'
}
@ -60,6 +64,9 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.cardview:cardview:1.0.0'
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 'com.afollestad.material-dialogs:input:3.3.0'
implementation 'com.airbnb.android:lottie:3.4.2'

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

@ -7,39 +7,46 @@ import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
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.input.getInputField
import com.afollestad.materialdialogs.input.input
import com.androidnetworking.AndroidNetworking
import com.androidnetworking.error.ANError
import com.androidnetworking.interfaces.StringRequestListener
import com.cyb3rko.techniklogger.recycler.ProjectEntryViewHolder
import com.cyb3rko.techniklogger.recycler.ProjectViewState
import com.cyb3rko.techniklogger.databinding.ActivityMainBinding
import com.cyb3rko.techniklogger.databinding.FragmentListingBinding
import com.cyb3rko.techniklogger.fragments.EinsatzPusherFragment
import com.cyb3rko.techniklogger.utils.About
import com.parse.ParseObject
import com.parse.ParseQuery
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.*
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 sharedPrefEditor: SharedPreferences.Editor
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
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)
sharedPrefEditor = sharedPref.edit()
@ -47,56 +54,8 @@ class MainActivity : AppCompatActivity() {
if (sharedPref.getString("name", "") == "") {
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()
}
@ -116,82 +75,12 @@ class MainActivity : AppCompatActivity() {
}
positiveButton(0, "Speichern") {
sharedPref.edit().putString("name", inputName.toString()).apply()
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))
sharedPref.edit().putString("name", inputName.toString()).commit()
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() {
@ -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 {
// 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) {
R.id.action_rename -> showNameDialog()
R.id.action_admin -> updateAdminStatus()
R.id.action_about -> startActivity(Intent(applicationContext, About::class.java))
// R.id.action_privacy_policy ->
// 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.Intent
import android.content.Context
import android.os.Bundle
import android.text.Html
import android.text.SpannableStringBuilder
import android.view.MenuItem
import android.util.Log
import android.view.LayoutInflater
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.cyb3rko.techniklogger.R
import com.cyb3rko.techniklogger.databinding.FragmentEinsatzPusherBinding
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat
import com.parse.ParseObject
import es.dmoral.toasty.Toasty
import kotlinx.android.synthetic.main.activity_einsatz_pusher.*
import java.sql.Time
import java.text.DecimalFormat
import java.text.SimpleDateFormat
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 var date = ""
@ -31,28 +38,29 @@ class EinsatzPusher : AppCompatActivity() {
private var duration = ""
private lateinit var location: String
private lateinit var name: String
private val simpleDateFormat = SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY)
private val simpleDateFormat = SimpleDateFormat("dd.MM.yyyy")
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
getBundleInformation()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_einsatz_pusher)
// 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 = FragmentEinsatzPusherBinding.inflate(inflater, container, false)
val root = binding.root
myContext = requireContext()
getArgumentInformation()
restoreInformation()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
val builder = MaterialDatePicker.Builder.datePicker().setTitleText("Datum")
val builder2 = MaterialTimePicker.Builder().setTimeFormat(TimeFormat.CLOCK_24H).setTitleText("Von")
val builder3 = MaterialTimePicker.Builder().setTimeFormat(TimeFormat.CLOCK_24H).setTitleText("Bis")
date_button.setOnClickListener {
if (date != "null") {
binding.dateButton.setOnClickListener {
if (date != "") {
val dateInMillis = simpleDateFormat.parse(date)!!.time
builder.setSelection(dateInMillis + 3600000)
builder.setSelection(dateInMillis + 7200000)
}
if (time != "null") {
if (time != "") {
val times = time.split(" - ")
builder2.setHour(times[0].split(":")[0].toInt())
.setMinute(times[0].split(":")[1].toInt())
@ -69,8 +77,8 @@ class EinsatzPusher : AppCompatActivity() {
var minutesInMillis: Long
picker.addOnPositiveButtonClickListener {
date = simpleDateFormat.format(Date(it))
date_view.text = Html.fromHtml("<b>Datum:</b><br/>${date}")
picker2.show(supportFragmentManager, picker2.tag)
binding.dateView.text = Html.fromHtml("<b>Datum:</b><br/>${date}")
activity?.let { it1 -> picker2.show(it1.supportFragmentManager, picker2.tag) }
}
picker2.addOnPositiveButtonClickListener {
hour = picker2.hour.toString()
@ -81,7 +89,7 @@ class EinsatzPusher : AppCompatActivity() {
minutesInMillis = picker2.minute.toLong() * 60000
time1 = Time(hoursInMillis + minutesInMillis)
tempTime += "${hour}:${minute} - "
picker3.show(supportFragmentManager, picker3.tag)
activity?.let { it1 -> picker3.show(it1.supportFragmentManager, picker3.tag) }
}
picker3.addOnPositiveButtonClickListener {
hour = picker3.hour.toString()
@ -95,30 +103,38 @@ class EinsatzPusher : AppCompatActivity() {
time = tempTime
duration = DecimalFormat("#.#").format((time2.time - time1.time) / 3600 / 1000.toFloat())
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") {
delete_button.visibility = View.VISIBLE
delete_button.setOnClickListener {
MaterialDialog(this)
if (childKey != "") {
binding.deleteButton.visibility = View.VISIBLE
binding.deleteButton.setOnClickListener {
MaterialDialog(myContext)
.show {
message(0, "Möchtest du diesen Einsatz entfernen?")
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")
}
}
}
finished_button.setOnClickListener {
val name = nameEditText.text.toString()
val location = locationEditText.text.toString()
binding.finishedButton.setOnClickListener {
val name = binding.nameEditText.text.toString()
val location = binding.locationEditText.text.toString()
if (name != "" && location != "" && time != "null") {
if (name != "" && location != "" && time != "") {
entry.put("name", name)
entry.put("ort", location)
val dateTimes = date.split(".")
@ -126,66 +142,54 @@ class EinsatzPusher : AppCompatActivity() {
if (time != "") dateTime += ",$time"
entry.put("datum", dateTime)
entry.put("dauer", duration.toFloat())
if (childKey == "null") {
if (childKey == "") {
entry.put("techniker", listOf<String>())
}
entry.saveInBackground()
finish()
startActivity(Intent(applicationContext, MainActivity::class.java))
entry.saveInBackground() {
if (it == null) {
findNavController().navigate(R.id.navigation_listing)
} else {
Toasty.error(myContext, "Fehler bei Speicherung").show()
Log.e("TechnikLogger.Einsätze", it.message.toString())
}
}
} 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() {
childKey = intent.extras?.getString("childKey").toString()
name = intent.extras?.getString("name").toString()
location = intent.extras?.getString("location").toString()
date = intent.extras?.getString("date").toString()
time = intent.extras?.getString("time").toString()
duration = intent.extras?.getString("duration").toString()
private fun getArgumentInformation() {
childKey = args.childKey
name = args.name
location = args.location
date = args.date
time = args.time
duration = args.duration
}
private fun restoreInformation() {
if (name != "null") {
nameEditText.text = SpannableStringBuilder(name)
if (name != "") {
binding.nameEditText.text = SpannableStringBuilder(name)
}
if (location != "null") {
locationEditText.text = SpannableStringBuilder(location)
if (location != "") {
binding.locationEditText.text = SpannableStringBuilder(location)
}
if (date != "null") {
date_view.text = Html.fromHtml("<b>Datum:</b><br/>${date}")
if (date != "") {
binding.dateView.text = Html.fromHtml("<b>Datum:</b><br/>${date}")
}
if (time != "null") {
duration_view.text = Html.fromHtml("<b>Dauer:</b> $time Uhr, $duration Stunden")
} else if (duration != "null") {
duration_view.text = Html.fromHtml("<b>Dauer:</b> $duration Stunden")
if (time != "") {
binding.durationView.text = Html.fromHtml("<b>Dauer:</b> $time Uhr, $duration Stunden")
} else if (duration != "") {
binding.durationView.text = Html.fromHtml("<b>Dauer:</b> $duration Stunden")
}
if (childKey == "null") {
if (childKey == "") {
entry = ParseObject("Einsatz")
} else {
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.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import android.view.*
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog
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.listItemsMultiChoice
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.ProjectTechnikerViewState
import com.parse.ParseObject
import com.parse.ParseQuery
import es.dmoral.toasty.Toasty
import kotlinx.android.synthetic.main.activity_main.*
import java.lang.IndexOutOfBoundsException
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.core.RecyclerViewHolder
@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 var adminMode = false
@ -38,16 +40,19 @@ class ProjectActivity : AppCompatActivity() {
private lateinit var sharedPref: SharedPreferences
private val techniker: MutableList<ProjectTechnikerViewState.ProjectTechniker> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
childKey = intent.extras?.getString("childKey").toString()
einsatz = ParseObject.createWithoutData("Einsatz", childKey)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_project)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
private val binding get() = _binding!!
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)
childKey = args.childKey
einsatz = ParseObject.createWithoutData("Einsatz", childKey)
adapter = adapterOf {
register(
layoutResource = R.layout.item_recycler_techniker,
@ -56,7 +61,7 @@ class ProjectActivity : AppCompatActivity() {
vh.textView.text = text.name
vh.itemView.setOnClickListener {
if (adminMode) {
MaterialDialog(this@ProjectActivity)
MaterialDialog(myContext)
.show {
message(text = "Möchtest du \'${text.name}\' entfernen?")
positiveButton(text = "Ja") {
@ -64,8 +69,8 @@ class ProjectActivity : AppCompatActivity() {
einsatz.put("techniker", techniker)
einsatz.saveInBackground()
adapter.notifyDataSetChanged()
this@ProjectActivity.recycler_view.scheduleLayoutAnimation()
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}"
binding.recyclerView.scheduleLayoutAnimation()
binding.technikerView.text = "Techniker: ${techniker.size}"
if (techniker.size == 0) showDivider(false)
}
negativeButton(text = "Abbrechen")
@ -96,35 +101,35 @@ class ProjectActivity : AppCompatActivity() {
techniker.add(ProjectTechnikerViewState.ProjectTechniker(it.getString("name")!!, it.objectId))
}
techniker.sortBy { it.name }
recycler_view.scheduleLayoutAnimation()
binding.recyclerView.scheduleLayoutAnimation()
adapter.notifyDataSetChanged()
techniker_view.text = "Techniker: ${techniker.size}"
binding.technikerView.text = "Techniker: ${techniker.size}"
showDivider()
} 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())
}
}
}
title_view.text = einsatz["name"].toString()
location_view.text = einsatz["ort"].toString()
binding.titleView.text = einsatz["name"].toString()
binding.locationView.text = einsatz["ort"].toString()
val dates = einsatz["datum"].toString().split(",")
val dateParts = dates[0].split(".")
val date = "${dateParts[2]}.${dateParts[1]}.${dateParts[0]}"
val time = if (dates.size > 1) ", ${dates[1]}" else ""
date_view.text = date + time
binding.dateView.text = date + time
} 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())
}
}
adapter.submitList(techniker as List<ProjectTechnikerViewState>?)
recycler_view.layoutManager = LinearLayoutManager(applicationContext)
recycler_view.adapter = adapter
binding.recyclerView.layoutManager = LinearLayoutManager(myContext)
binding.recyclerView.adapter = adapter
add_button.setOnClickListener {
binding.addButton.setOnClickListener {
val name = sharedPref.getString("name", "invalid")!!
if (!adminMode) selfAdd(name) else bothAdd(name)
}
@ -132,9 +137,9 @@ class ProjectActivity : AppCompatActivity() {
emptyCheck()
if (adminMode) {
reset_button.visibility = View.VISIBLE
reset_button.setOnClickListener {
MaterialDialog(this).show {
binding.resetButton.visibility = View.VISIBLE
binding.resetButton.setOnClickListener {
MaterialDialog(myContext).show {
message(text = "Möchtest du alle eingetragenen Techniker entfernen?")
positiveButton(text = "Ja") {
einsatz.put("techniker", listOf<String>())
@ -142,12 +147,14 @@ class ProjectActivity : AppCompatActivity() {
techniker.clear()
adapter.notifyDataSetChanged()
showDivider(false)
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}"
binding.technikerView.text = "Techniker: ${techniker.size}"
}
negativeButton(text = "Abbrechen")
}
}
}
return root
}
private fun technikerExists(name: String): Boolean {
@ -160,7 +167,7 @@ class ProjectActivity : AppCompatActivity() {
}
private fun bothAdd(name: String) {
MaterialDialog(this)
MaterialDialog(myContext)
.show {
message(text = "Möchtest du nur dich oder auch andere Techniker eintragen?")
positiveButton(text = "Mich") {
@ -175,7 +182,7 @@ class ProjectActivity : AppCompatActivity() {
private fun selfAdd(name: String, skip: Boolean = false) {
if (!technikerExists(name)) {
if (!skip) {
MaterialDialog(this).show {
MaterialDialog(myContext).show {
message(text = "Möchtest du dich als involvierter Techniker eintragen?")
positiveButton(text = "Ja") {
val entry = ParseObject.createWithoutData("Einsatz", childKey)
@ -185,8 +192,8 @@ class ProjectActivity : AppCompatActivity() {
techniker.sortBy { it.name }
adapter.notifyDataSetChanged()
showDivider(true)
this@ProjectActivity.recycler_view.scheduleLayoutAnimation()
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}"
binding.recyclerView.scheduleLayoutAnimation()
binding.technikerView.text = "Techniker: ${techniker.size}"
}
negativeButton(text = "Abbrechen")
}
@ -198,11 +205,11 @@ class ProjectActivity : AppCompatActivity() {
techniker.sortBy { it.name }
adapter.notifyDataSetChanged()
showDivider(true)
this@ProjectActivity.recycler_view.scheduleLayoutAnimation()
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}"
binding.recyclerView.scheduleLayoutAnimation()
binding.technikerView.text = "Techniker: ${techniker.size}"
}
} else {
MaterialDialog(this)
MaterialDialog(myContext)
.show {
message(text = "Du bist bereits eingetragen.")
positiveButton(text = "Ok")
@ -231,7 +238,7 @@ class ProjectActivity : AppCompatActivity() {
}
}
val intArray = currentSelection.toIntArray()
MaterialDialog(this@ProjectActivity).show {
MaterialDialog(myContext).show {
listItemsMultiChoice(items = names, initialSelection = intArray, disabledIndices = intArray)
positiveButton(text = "Hinzufügen") {
it.uncheckItems(intArray)
@ -248,34 +255,34 @@ class ProjectActivity : AppCompatActivity() {
techniker.sortBy { it.name }
adapter.notifyDataSetChanged()
showDivider(true)
this@ProjectActivity.recycler_view.scheduleLayoutAnimation()
this@ProjectActivity.techniker_view.text = "Techniker: ${techniker.size}"
binding.recyclerView.scheduleLayoutAnimation()
binding.technikerView.text = "Techniker: ${techniker.size}"
}
negativeButton(text = "Abbrechen") {
addTechniker.clear()
}
}
} 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())
}
}
}
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() {
if (techniker.isEmpty()) {
divider.visibility = View.GONE
binding.divider.visibility = View.GONE
}
}
private fun showNameDialog() {
val currentName = getSharedPreferences("Safe", 0).getString("name", "")
val currentName = myContext.getSharedPreferences("Safe", 0).getString("name", "")
MaterialDialog(this)
MaterialDialog(myContext)
.cancelable(false)
.title(0, "Bitte gebe deinen Namen ein")
.show {
@ -288,32 +295,10 @@ class ProjectActivity : AppCompatActivity() {
}
positiveButton {
getSharedPreferences("Safe", 0).edit().putString("name", inputName.toString()).apply()
myContext.getSharedPreferences("Safe", 0).edit().putString("name", inputName.toString()).apply()
}
}
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"?>
<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:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
<fragment
android:id="@+id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
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" />
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation" />
<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>
</RelativeLayout>

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -80,7 +81,7 @@
android:layout_height="wrap_content"
android:text="Datum:\n---"
android:textAlignment="center"
android:layout_gravity="center_vertical"
android:layout_gravity="center"
android:foregroundGravity="center_vertical"
android:layout_marginStart="20dp"
android:textSize="16sp"/>
@ -123,7 +124,7 @@
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:textAlignment="center"
android:layout_gravity="center_vertical"
android:layout_gravity="center"
android:foregroundGravity="center_vertical"
android:layout_marginStart="20dp"
android:textSize="16sp"/>
@ -155,6 +156,7 @@
android:visibility="gone"
style="@style/Widget.MaterialComponents.Button"
android:textSize="12sp"
android:text="Einsatz entfernen" />
android:text="Einsatz entfernen"
tools:visibility="visible" />
</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"
app:showAsAction="never" />
<item
android:id="@+id/action_admin"
android:title="Adminstatus abrufen"
app:showAsAction="never" />
<item
android:id="@+id/action_about"
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.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libraries_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
// in the individual module build.gradle files

Loading…
Cancel
Save