diff --git a/app/build.gradle b/app/build.gradle index 865a42e..4a1726f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b57f0b9..5e38d6d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,14 +24,10 @@ - - diff --git a/app/src/main/java/com/cyb3rko/techniklogger/MainActivity.kt b/app/src/main/java/com/cyb3rko/techniklogger/MainActivity.kt index bd3d4c4..c6b8201 100644 --- a/app/src/main/java/com/cyb3rko/techniklogger/MainActivity.kt +++ b/app/src/main/java/com/cyb3rko/techniklogger/MainActivity.kt @@ -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 = 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 { - 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?) - 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>) { - val query = ParseQuery.getQuery("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("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 -> diff --git a/app/src/main/java/com/cyb3rko/techniklogger/ProjectActivityBuilder.kt b/app/src/main/java/com/cyb3rko/techniklogger/ProjectActivityBuilder.kt deleted file mode 100644 index fb38d9f..0000000 --- a/app/src/main/java/com/cyb3rko/techniklogger/ProjectActivityBuilder.kt +++ /dev/null @@ -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) - } -} diff --git a/app/src/main/java/com/cyb3rko/techniklogger/EinsatzPusher.kt b/app/src/main/java/com/cyb3rko/techniklogger/fragments/EinsatzPusherFragment.kt similarity index 53% rename from app/src/main/java/com/cyb3rko/techniklogger/EinsatzPusher.kt rename to app/src/main/java/com/cyb3rko/techniklogger/fragments/EinsatzPusherFragment.kt index b0c2dcc..5ef2a0a 100644 --- a/app/src/main/java/com/cyb3rko/techniklogger/EinsatzPusher.kt +++ b/app/src/main/java/com/cyb3rko/techniklogger/fragments/EinsatzPusherFragment.kt @@ -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("Datum:
${date}") - picker2.show(supportFragmentManager, picker2.tag) + binding.dateView.text = Html.fromHtml("Datum:
${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("Dauer: $time Uhr, $duration Stunden") + binding.durationView.text = Html.fromHtml("Dauer: $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()) } - 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("Datum:
${date}") + if (date != "") { + binding.dateView.text = Html.fromHtml("Datum:
${date}") } - if (time != "null") { - duration_view.text = Html.fromHtml("Dauer: $time Uhr, $duration Stunden") - } else if (duration != "null") { - duration_view.text = Html.fromHtml("Dauer: $duration Stunden") + if (time != "") { + binding.durationView.text = Html.fromHtml("Dauer: $time Uhr, $duration Stunden") + } else if (duration != "") { + binding.durationView.text = Html.fromHtml("Dauer: $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)) - } } diff --git a/app/src/main/java/com/cyb3rko/techniklogger/fragments/ListingFragment.kt b/app/src/main/java/com/cyb3rko/techniklogger/fragments/ListingFragment.kt new file mode 100644 index 0000000..34e8571 --- /dev/null +++ b/app/src/main/java/com/cyb3rko/techniklogger/fragments/ListingFragment.kt @@ -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 = 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 { + 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?) + 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>) { + data.clear() + val query = ParseQuery.getQuery("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("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()) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/cyb3rko/techniklogger/ProjectActivity.kt b/app/src/main/java/com/cyb3rko/techniklogger/fragments/ProjectFragment.kt similarity index 71% rename from app/src/main/java/com/cyb3rko/techniklogger/ProjectActivity.kt rename to app/src/main/java/com/cyb3rko/techniklogger/fragments/ProjectFragment.kt index e73abc6..3a04e1d 100644 --- a/app/src/main/java/com/cyb3rko/techniklogger/ProjectActivity.kt +++ b/app/src/main/java/com/cyb3rko/techniklogger/fragments/ProjectFragment.kt @@ -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> private var adminMode = false @@ -38,16 +40,19 @@ class ProjectActivity : AppCompatActivity() { private lateinit var sharedPref: SharedPreferences private val techniker: MutableList = 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?) - 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()) @@ -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) - } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 49771cc..2a72667 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,59 +1,17 @@ - + android:layout_height="match_parent"> - + android:layout_height="match_parent" + app:defaultNavHost="true" + app:navGraph="@navigation/mobile_navigation" /> - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_einsatz_pusher.xml b/app/src/main/res/layout/fragment_einsatz_pusher.xml similarity index 96% rename from app/src/main/res/layout/activity_einsatz_pusher.xml rename to app/src/main/res/layout/fragment_einsatz_pusher.xml index 9e5d841..b64f177 100644 --- a/app/src/main/res/layout/activity_einsatz_pusher.xml +++ b/app/src/main/res/layout/fragment_einsatz_pusher.xml @@ -1,6 +1,7 @@ @@ -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" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_listing.xml b/app/src/main/res/layout/fragment_listing.xml new file mode 100644 index 0000000..49771cc --- /dev/null +++ b/app/src/main/res/layout/fragment_listing.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_project.xml b/app/src/main/res/layout/fragment_project.xml similarity index 100% rename from app/src/main/res/layout/activity_project.xml rename to app/src/main/res/layout/fragment_project.xml diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 39cfb68..cc9d304 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -7,11 +7,6 @@ android:title="Namen ändern" app:showAsAction="never" /> - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 5013399..7cafb1d 100644 --- a/build.gradle +++ b/build.gradle @@ -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