Skip to content

Instantly share code, notes, and snippets.

@kyodgorbek
Last active January 11, 2023 16:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kyodgorbek/401284de161d215a5c13732cebd098cd to your computer and use it in GitHub Desktop.
Save kyodgorbek/401284de161d215a5c13732cebd098cd to your computer and use it in GitHub Desktop.
/*
* Copyright (C) 2019 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chargeatfriends.android.network
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import androidx.core.app.NotificationCompat
import com.chargeatfriends.android.MainActivity
import com.chargeatfriends.android.R
import com.chargeatfriends.android.ui.approve.ApprovalActivity
// Notification ID.
private val NOTIFICATION_ID = 0
private val REQUEST_CODE = 0
private val FLAGS = 0
private lateinit var contentIntent: Intent
// TODO: Step 1.1 extension function to send messages (GIVEN)
/**
* Builds and delivers the notification.
*
* @param messageBody, notification text.
* @param context, activity context.
*/
fun NotificationManager.sendNotification(messageBody: String, title: String, applicationContext: Context, color: Int, targetAction: Int) {
// TODO: Step 1.11 create intent
when(targetAction){
R.id.mainActivity ->{
contentIntent = Intent(applicationContext, MainActivity::class.java)
}
R.id.approvalActivity->{
contentIntent = Intent(applicationContext, ApprovalActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
}
else ->{
contentIntent = Intent(applicationContext, MainActivity::class.java)
}
}
// TODO: Step 1.12 create PendingIntent
val contentPendingIntent = PendingIntent.getActivity(
applicationContext,
NOTIFICATION_ID,
contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
// TODO: Step 2.0 add style
val eggImage = BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.ic_launcher_round
)
val bigPicStyle = NotificationCompat.BigPictureStyle()
.bigPicture(eggImage)
.bigLargeIcon(null)
// TODO: Step 2.2 add snooze action
// val snoozeIntent = Intent(applicationContext, SnoozeReceiver::class.java)
// val snoozePendingIntent: PendingIntent =
// PendingIntent.getBroadcast(applicationContext, REQUEST_CODE, snoozeIntent, FLAGS)
// TODO: Step 1.2 get an instance of NotificationCompat.Builder
// Build the notification
val builder = NotificationCompat.Builder(
applicationContext,
// TODO: Step 1.8 use the new 'breakfast' notification channel
applicationContext.getString(R.string.notification_channel)
)
// TODO: Step 1.3 set title, text and icon to builder
.setSmallIcon(R.drawable.ic_logo_24dp)
.setColor(color)
.setContentTitle(title)
.setContentText(messageBody)
// TODO: Step 1.13 set content intent
.setContentIntent(contentPendingIntent)
// TODO: Step 2.1 add style to builder
.setStyle(bigPicStyle)
.setLargeIcon(eggImage)
// TODO: Step 2.3 add snooze action
// .addAction(
// R.drawable.ic_launcher_foreground,
// applicationContext.getString(R.string.notification_snooze),
// snoozePendingIntent
// )
// TODO: Step 2.5 set priority
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
// TODO Step 1.4 call notify
// Deliver the notification
notify(NOTIFICATION_ID, builder.build())
}
// TODO: Step 1.14 Cancel all notifications
/**
* Cancels all notifications.
*
*/
fun NotificationManager.cancelNotifications() {
cancelAll()
}
class PushNotificationService : FirebaseMessagingService() {
/**
* Called when message is received.
*
* @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
// [START receive_message]
override fun onMessageReceived(remoteMessage: RemoteMessage) {
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
Log.d(TAG, "From: ${remoteMessage?.from}")
// TODO Step 3.5 check messages for data
// Check if message contains a data payload.
var title = resources.getString(R.string.hi)
var color = ContextCompat.getColor(this, R.color.colorCaF)
var targetAction = R.id.mainActivity;
remoteMessage?.data?.let {
if (it.containsKey("action")) {
val intent = Intent(it["action"])
intent.putExtra("guid", it["guid"])
intent.putExtra("state", it["state"])
when (it["action"]) {
START -> {
val broadcaster = LocalBroadcastManager.getInstance(baseContext)
intent.putExtra("meterstart", it["meterstart"])
intent.putExtra("updatedate", it["updatedate"])
title = "Ladevorgang gestartet"
broadcaster.sendBroadcast(intent)
}
END -> {
val broadcaster = LocalBroadcastManager.getInstance(baseContext)
intent.putExtra("meterend", it["meterend"])
intent.putExtra("updatedate", it["updatedate"])
title = "Ladevorgang beendet"
broadcaster.sendBroadcast(intent)
}
END_PAYMENT -> {
val broadcaster = LocalBroadcastManager.getInstance(baseContext)
intent.putExtra("amount", it["amount"])
intent.putExtra("updatedate", it["updatedate"])
title = "Zahlung erfolgt"
broadcaster.sendBroadcast(intent)
}
VERIFICATION_APPROVED -> {
val broadcaster = LocalBroadcastManager.getInstance(baseContext)
color = ContextCompat.getColor(this, R.color.colorAccent)
targetAction = R.id.navigation_charge;
intent.putExtra("amount", it["amount"])
intent.putExtra("updatedate", it["updatedate"])
title = "Zählerstand bestätigt"
broadcaster.sendBroadcast(intent)
}
VERIFICATION_REQUESTED -> {
val broadcaster = LocalBroadcastManager.getInstance(baseContext)
color = ContextCompat.getColor(this, R.color.colorAccent)
targetAction = R.id.approvalActivity;
intent.putExtra("start", it["start"])
appCommon.RemoteBookingGuid = UUID.fromString(it["guid"])
appCommon.RemotBookkingIsCpo = true
try {
val _state: Long = it["state"]!!.toLong()
if (_state > 0) {
val iState = if ((BookingState.ChargingEnded.bitmask and _state) > 0) 1 else 0
if (iState == 1) {
title = "Zählerstande bestätigen"
intent.putExtra("end", it["end"])
} else {
title = "Start-Zählerstand bestätigen"
}
}
broadcaster.sendBroadcast(intent)
} catch (ex: Exception) {
}
}
VERIFICATION_REJECTED -> {
val broadcaster = LocalBroadcastManager.getInstance(baseContext)
color = ContextCompat.getColor(this, R.color.colorAccent)
targetAction = R.id.approvalActivity;
intent.putExtra("start", it["start"])
appCommon.RemoteBookingGuid = UUID.fromString(it["guid"])
appCommon.RemotBookkingIsCpo = false
try {
val _state: Long = it["state"]!!.toLong()
if (_state > 0) {
val iState = if ((BookingState.ChargingEnded.bitmask and _state) > 0) 1 else 0
title = "Zählerstände überprüfen"
}
broadcaster.sendBroadcast(intent)
} catch (ex: Exception) {
}
}
CORRECTION_REJECTED -> {
val broadcaster = LocalBroadcastManager.getInstance(baseContext)
color = ContextCompat.getColor(this, R.color.colorAccent)
targetAction = R.id.approvalActivity;
intent.putExtra("start", it["start"])
appCommon.RemoteBookingGuid = UUID.fromString(it["guid"])
appCommon.RemotBookkingIsCpo = true
try {
val _state: Long = it["state"]!!.toLong()
if (_state > 0) {
val iState = if ((BookingState.ChargingEnded.bitmask and _state) > 0) 1 else 0
title = resources.getString(R.string.correction_rejected)
}
broadcaster.sendBroadcast(intent)
} catch (ex: Exception) {
}
}
CHARGING_STARTED -> {
color = ContextCompat.getColor(this, R.color.colorActive)
title = "Ladevorgang gestartet"
}
THREE_D_AUTH_REQUIRED ->{
// 3d auth webview
}
PAYMENT_START_NEXT ->{
// payment is blocked
// you can start charging
// ocpp charged will start at backend
// manual updated ui enter meta value
}
}
}
Log.d(TAG, "Message data payload: " + remoteMessage.data)
}
// TODO Step 3.6 check messages for notification and call sendNotification
// Check if message contains a notification payload.
remoteMessage?.notification?.let {
Log.d(TAG, "Message Notification Body: ${it.body}")
sendNotification(it.body!!, title, color, targetAction)
}
}
// [END receive_message]
//TODO Step 3.2 log registration token
// [START on_new_token]
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
override fun onNewToken(token: String) {
Log.d(TAG, "Refreshed token: $token")
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
appCommon.sendRegistrationToServer(token)
}
// [END on_new_token]
/**
* Persist token to third-party servers.
*
* @param token The new token.
*/
/**
* Create and show a simple notification containing the received FCM message.
*
* @param messageBody FCM message body received.
*/
private fun sendNotification(messageBody: String, title: String, color: Int, target: Int) {
val notificationManager = ContextCompat.getSystemService(
applicationContext,
NotificationManager::class.java
) as NotificationManager
notificationManager.sendNotification(messageBody, title, applicationContext, color, target)
}
companion object {
private const val TAG = "MyFirebaseMsgService"
}
}
package com.chargeatfriends.android.ui.reserve
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.os.Bundle
import android.text.format.DateFormat
import android.text.method.LinkMovementMethod
import android.util.DisplayMetrics
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.chargeatfriends.android.R
import com.chargeatfriends.android.model.AccessProfile
import com.chargeatfriends.android.model.Booking
import com.chargeatfriends.android.model.ChargePointType
import com.chargeatfriends.android.model.appCommon
import com.chargeatfriends.android.model.stripe.BackendApiFactory
import com.chargeatfriends.android.network.EndToNextStartMinutes
import com.chargeatfriends.android.network.StartToNextStartMinutes
import com.chargeatfriends.android.network.baseUrl
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.reflect.TypeToken
import com.squareup.picasso.Picasso
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.lang.reflect.Type
import java.time.*
import java.time.format.DateTimeFormatter
import java.util.*
import kotlin.math.pow
import kotlin.math.roundToInt
class ReserveFragment : Fragment(R.layout.reserve_fragment), DatePickerDialog.OnDateSetListener,
TimePickerDialog.OnTimeSetListener, SeekBar.OnSeekBarChangeListener {
// private lateinit var viewModel: ReserveViewModel
lateinit var StationNameView: TextView
lateinit var OpenHoursTextView: TextView
lateinit var TarifTextView: TextView
lateinit var PvTarifTextView: TextView
lateinit var PowerTextView: TextView
lateinit var PvHoursTextView: TextView
lateinit var startButton: Button
lateinit var BookNowButton: Button
var isAvailable: Boolean = false
var accesProfileLoaded: Boolean = false
lateinit var scheduleConflictText: TextView
lateinit var agbConstraint: ConstraintLayout
lateinit var PvTarifLayout: ConstraintLayout
lateinit var agbText: TextView
lateinit var durationSlider: SeekBar
lateinit var linearLayoutStartTime: LinearLayout
lateinit var LinearLayoutTiming: LinearLayout
lateinit var timeSlots: IntArray
lateinit var DayDropdown: Spinner
var duration: Int = 4
var booking = Booking()
lateinit var agbSwitch: androidx.appcompat.widget.SwitchCompat
private lateinit var ThumbnailImageView: ImageView
var StartTime: LocalTime = LocalTime.now().plusSeconds(3600)
var EndTime: LocalTime = LocalTime.now().plusSeconds(3600 + appCommon.defaultChargeTime)
var StartDate: LocalDate = LocalDate.now()
val dateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val timeFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")
// val dateParseFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("d.M.yyyy")
// val timeParseFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("H:m")
/* override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this).get(ReserveViewModel::class.java)
// TODO: Use the ViewModel
if (appCommon.isAdhocBooking) {
StartTime = LocalTime.now()
EndTime = LocalTime.now().plusSeconds(3600 + appCommon.defaultChargeTime)
}
}*/
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.reserve_fragment, container, false)
/* val textView: TextView = root.findViewById(R.id.text_notifications)
settingsViewModel.text.observe(viewLifecycleOwner, Observer {
textView.text = it
})*/
if (appCommon.getLoginToken().isEmpty()) {
findNavController().navigate(R.id.navigation_settings_login)
}
if (appCommon.isChargePointInitialized()) {
/// Head Section Name, Power
StationNameView = root.findViewById(R.id.StationNameTextView) as TextView
StationNameView.text = appCommon.CurrentChargePoint.CpName
PowerTextView = root.findViewById(R.id.PowerTextView) as TextView
PowerTextView.text = String.format(Locale.GERMAN, "%.1f", appCommon.CurrentChargePoint.Power) + " kW"
// ConnectorNameView = root.findViewById(R.id.ConnectorNameTextView) as TextView
// ConnectorNameView.text = appCommon.CurrentChargePoint.Name
/// Open Hours - Tarifs
OpenHoursTextView = root.findViewById(R.id.OpenHoursTextView) as TextView
TarifTextView = root.findViewById(R.id.TarifTextView) as TextView
TarifTextView.text = String.format(Locale.GERMAN, "%.0f", appCommon.CurrentChargePoint.Tarif) + " Ct/kWh"
PvTarifLayout = root.findViewById(R.id.PvTarifLayout) as ConstraintLayout
PvTarifLayout.isVisible = false
PvTarifTextView = root.findViewById(R.id.PvTarifTextView) as TextView
PvTarifTextView.text = String.format(Locale.GERMAN, "%.0f", appCommon.CurrentChargePoint.SunShineRate) + " Ct/kWh"
PvHoursTextView = root.findViewById(R.id.PvHoursTextView) as TextView
PvTarifTextView.text = ""
/// Timing
LinearLayoutTiming = root.findViewById(R.id.LinearLayoutTiming) as LinearLayout
LinearLayoutTiming.isVisible = !appCommon.CurrentChargePoint.hasType(ChargePointType.AdHoc)
// Dropdown Days
DayDropdown = root.findViewById(R.id.DayDropdown)
val tomorrow = LocalDateTime.now().plusDays(1)
val atomorrow = LocalDateTime.now().plusDays(2)
/* Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter.createFromResource(
requireContext(),
R.array.DefaultDateValues,
android.R.layout.simple_spinner_item
).also { adapter ->
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
// Apply the adapter to the spinner
spinner.adapter = adapter
}*/
timeSlots = intArrayOf(1, 2, 3, 4, 5, 6, 8, 10, 12)
val spinnerData = arrayOf("Heute", tomorrow.format(dateFormat), "" + atomorrow.format(dateFormat))
DayDropdown.adapter = ArrayAdapter<String>(requireContext(), android.R.layout.simple_spinner_dropdown_item, spinnerData)
val startTime = if (appCommon.isAdhocBooking) {
OffsetDateTime.now()
} else {
OffsetDateTime.now().plusSeconds(3600)
}
booking.STime = OffsetDateTime.from(startTime)
/* editStartTime.text = StartTime.hour.toString()+":"+ StartTime.minute.toString()
editStartTime.text = StartTime.format(timeFormat)
editStartTime.setOnClickListener(clickListener)
*/
startButton = root.findViewById(R.id.start_button) as Button
startButton.setOnClickListener(clickListener)
// editEndTime = root.findViewById(R.id.editEndTime) as TextView
EndTime = if (appCommon.CurrentChargePoint.hasType(ChargePointType.AdHoc)) { // pure Ad Hoc station
LocalTime.now().plusSeconds(3600 * 8)
} else if (appCommon.isAdhocBooking) { // Ad hoc @ reservable station
LocalTime.now().plusSeconds(3600 * 4)
} else { // reserved booking
LocalTime.now().plusSeconds(3600 + 3600 * 4)
}
durationSlider = root.findViewById(R.id.durationSlider) as SeekBar
/// Booknow Button and AGB Section
/*
editEndTime.text = EndTime.format(timeFormat)
editEndTime.setOnClickListener(clickListener)
endButton = root.findViewById(R.id.end_button) as Button
endButton.setOnClickListener(clickListener)
editTextDate = root.findViewById(R.id.editTextDate) as TextView
editTextDate.text = StartDate.format(dateFormat)
*/
BookNowButton = root.findViewById(R.id.BookNowButton) as Button
if (appCommon.isAdhocBooking) {
linearLayoutStartTime = root.findViewById(R.id.linearLayoutStartTime) as LinearLayout
linearLayoutStartTime.isVisible = false
BookNowButton.text = resources.getString(R.string.charge_now)
StartTime = LocalTime.now()
} else if (appCommon.CurrentChargePoint.hasType(ChargePointType.AdHoc)) {
BookNowButton.text = "nur Direktladen möglich"
} else {
BookNowButton.text = resources.getString(R.string.book_now)
StartTime = LocalTime.now().plusSeconds(3600 * 1)
startButton.text = StartTime.format(timeFormat)
}
agbSwitch = root.findViewById(R.id.switchAgb) as androidx.appcompat.widget.SwitchCompat
agbSwitch.isChecked = false
BookNowButton.isEnabled = false
scheduleConflictText = root.findViewById(R.id.scheduleConflictText) as TextView
agbConstraint = root.findViewById(R.id.agbConstraint) as ConstraintLayout
BookNowButton.setOnClickListener(clickListener)
agbSwitch.setOnClickListener(clickListener)
agbText = root.findViewById(R.id.AgbText) as TextView
agbText.movementMethod = LinkMovementMethod.getInstance()
/// Background Image
ThumbnailImageView = root.findViewById(R.id.imageView) as ImageView
val displayMetrics = DisplayMetrics()
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
val display = requireActivity().display
display?.getRealMetrics(displayMetrics)
} else {
@Suppress("DEPRECATION")
val display = requireActivity().windowManager.defaultDisplay
@Suppress("DEPRECATION")
display.getMetrics(displayMetrics)
}
val height = displayMetrics.heightPixels - 32 - 60
val width = displayMetrics.widthPixels
Picasso.get()
.load(appCommon.CurrentChargePoint.ThumbnailUrl)
// .placeholder(R.drawable.ic_camera_grey_100dp)
// .error(R.drawable.ic_notifications_black_24dp)
.resize(width, height)
.centerCrop()
.into(ThumbnailImageView)
this.durationSlider!!.setOnSeekBarChangeListener(this)
checkAvailability()
getAccessProfile()
}
return root
}
private fun enableBookNowButton(enabled: Boolean) {
BookNowButton.isEnabled = agbSwitch.isChecked and enabled
updateUiByExistingBookings()
}
val clickListener = View.OnClickListener { view ->
// throw RuntimeException("Test Crash") // Force a crash
when (view.id) {
R.id.switchAgb -> {
enableBookNowButton(isAvailable)
}
R.id.BookNowButton -> {
val chargePoint = appCommon.CurrentChargePoint
// booking.Token = appCommon.getLoginToken()
booking.FriendGuid = appCommon.FriendGuid
booking.CpGuid = chargePoint.Guid
// val StartDate = LocalDate.parse(editTextDate.text, dateParseFormat)
var StartDateTime = LocalDateTime.now()
var EndDateTime = LocalDateTime.now().plusHours(3)
StartDate = LocalDate.now().plusDays(DayDropdown.selectedItemPosition.toLong())
EndTime = StartTime.plusHours(duration.toLong())
try {
// StartTime = LocalTime.parse(editStartTime.text, timeParseFormat)
// EndTime = LocalTime.parse(editEndTime.text, timeParseFormat)
StartDateTime = LocalDateTime.of(StartDate, StartTime)
EndDateTime = LocalDateTime.of(StartDate, EndTime)
} catch (err: Exception) {
}
val odt = OffsetDateTime.now()
val zoneOffset = odt.offset
booking.STime = OffsetDateTime.of(StartDateTime, zoneOffset)
booking.ETime = OffsetDateTime.of(EndDateTime, zoneOffset)
booking.InsertDate = OffsetDateTime.now()
booking.UpdateDate = OffsetDateTime.now()
booking.Name = chargePoint.Name
booking.ServiceFee = chargePoint.ServieFee
booking.kWhPrice = chargePoint.Tarif
if (appCommon.getLoginToken().length > 0) {
CreateBooking(booking)
// findNavController().navigateUp()
} else {
findNavController().navigate(R.id.navigation_settings_login)
}
}
R.id.start_button -> {
currentTimeSet = 0
val timePickerDialog = TimePickerDialog(
requireContext(), this, StartTime.hour, StartTime.minute,
DateFormat.is24HourFormat(requireContext())
)
timePickerDialog.show()
}
}
}
var currentTimeSet: Int = 0 // 0: Start, 1: End
override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {
StartDate = LocalDate.of(year, month, dayOfMonth)
// editTextDate.text = StartDate.format(dateFormat)
}
override fun onTimeSet(view: TimePicker?, hourOfDay: Int, minute: Int) {
if (currentTimeSet == 0) {
StartTime = LocalTime.of(hourOfDay, minute)
startButton.text = StartTime.format(timeFormat)
} else {
}
checkTimes()
checkAvailability()
}
private fun checkTimes() {
if (StartTime < LocalTime.now()) {
StartTime = LocalTime.now()
startButton.text = StartTime.format(timeFormat)
}
if (appCommon.isAdhocBooking) {
//adhoc booking for at least 15 minutes
if (StartTime.plusMinutes(15) > EndTime) {
EndTime = StartTime.plusMinutes(15)
startButton.text = EndTime.format(timeFormat)
}
} else {
//reserve for at least one hour
if (StartTime.plusHours(1) > EndTime) {
EndTime = StartTime.plusHours(1)
startButton.text = EndTime.format(timeFormat)
}
}
}
val dayFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")
private fun updateUiByExistingBookings() {
if (!isAvailable) {
val odt = OffsetDateTime.now()
val zoneOffset = odt.offset
// val firstBooking = OffsetDateTime.of( bookingsJson[0].STime?.minusMinutes(60)?.toLocalDateTime(), zoneOffset)
// val lastBooking = OffsetDateTime.of(bookingsJson[bookingsJson.size - 1].ETime?.plusMinutes(15)?.toLocalDateTime(), zoneOffset)
if (this::bookingsJson.isInitialized) {
scheduleConflictText.text =
"verfügbar vor " + bookingsJson[0].STime?.minusMinutes(60)?.localFormat() + " oder nach " + bookingsJson[bookingsJson.size - 1].ETime?.plusMinutes(15)?.localFormat() + " Uhr"
}
scheduleConflictText.isVisible = true
agbConstraint.alpha = 0.0f
BookNowButton.isVisible = false
setBookNowButtonState("Ladepunkt belegt", false, R.color.colorFalse, R.color.white)
} else {
scheduleConflictText.isVisible = false
BookNowButton.isVisible = true
agbConstraint.alpha = 1.0f
if (appCommon.isAdhocBooking) {
setBookNowButtonState(resources.getString(R.string.charge_now), agbSwitch.isChecked, R.color.colorOkDark, R.color.white)
} else if (appCommon.CurrentChargePoint.hasType(ChargePointType.AdHoc)) {
setBookNowButtonState("nur Direktladen möglich", false, R.color.TextMedium, R.color.white)
agbConstraint.alpha = 0.0f
} else {
setBookNowButtonState(resources.getString(R.string.book_now), agbSwitch.isChecked, R.color.colorOkDark, R.color.white)
}
}
}
private fun setBookNowButtonState(text: String, enabled: Boolean, bgColor: Int, tColor: Int) {
BookNowButton.text = text
BookNowButton.isEnabled = enabled
if (enabled) {
BookNowButton.setBackgroundColor(ContextCompat.getColor(requireContext(), bgColor))
BookNowButton.setTextColor(ContextCompat.getColor(requireContext(), tColor))
} else {
BookNowButton.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.SwitchOff))
BookNowButton.setTextColor(ContextCompat.getColor(requireContext(), R.color.Disabled))
}
}
private fun OffsetDateTime.localFormat(): String? {
val dayFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")
return this.atZoneSameInstant(OffsetDateTime.now().toZonedDateTime().zone)?.format(dayFormatter)
}
private lateinit var bookingsJson: List<Booking>
private lateinit var accessProfileList: List<AccessProfile>
private val listOfBookings = object : TypeToken<ArrayList<Booking?>?>() {}.type
private val listOfAccessProfiles = object : TypeToken<ArrayList<AccessProfile?>?>() {}.type
private fun checkAvailability() {
val odt = OffsetDateTime.now()
val zoneOffset = odt.offset
val sTime: OffsetDateTime = OffsetDateTime.of(StartDate, StartTime, zoneOffset)
val eTime: OffsetDateTime = OffsetDateTime.of(StartDate, EndTime, zoneOffset)
CoroutineScope(Dispatchers.IO).launch {
val response =
kotlin.runCatching {
backendApi
.getBookingAvailability(
appCommon.getLoginToken(),
appCommon.CurrentChargePoint.Guid.toString(),
sTime.toString(),
sTime.toString()
)
.string()
}
withContext(Dispatchers.Main) {
response.fold(
onSuccess = {
Log.d("checkAvailability-Success", it)
var gSon = GsonBuilder()
// .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting()
.registerTypeAdapter(
OffsetDateTime::class.java,
JsonDeserializer { json: JsonElement, type: Type?, context: JsonDeserializationContext? -> OffsetDateTime.parse(json.asString) } as JsonDeserializer<OffsetDateTime>)
.create()
bookingsJson = gSon.fromJson<List<Booking>>(it, listOfBookings).sortedBy { booking -> booking.STime?.toEpochSecond() }
if (bookingsJson != null && bookingsJson.count() > 0) {
isAvailable = !(bookingsJson.any { b ->
(b.StartTime == null && (
(b.STime?.minusMinutes(StartToNextStartMinutes)?.toEpochSecond()!! < sTime.toEpochSecond()) and (b.ETime?.plusMinutes(EndToNextStartMinutes)
?.toEpochSecond()!! > sTime.toEpochSecond())
or ((b.STime?.minusMinutes(StartToNextStartMinutes)?.toEpochSecond()!! < eTime.toEpochSecond()) and (b.ETime?.plusMinutes(EndToNextStartMinutes)
?.toEpochSecond()!! > eTime.toEpochSecond()))
or ((b.STime?.toEpochSecond()!! > sTime.toEpochSecond()) and (b.ETime?.plusMinutes(EndToNextStartMinutes)?.toEpochSecond()!! < eTime.toEpochSecond()))
)
) or (b.StartTime != null && b.EndTime == null && (
(b.StartTime?.toEpochSecond()!! < sTime.toEpochSecond()) and (b.ETime?.plusMinutes(EndToNextStartMinutes)?.toEpochSecond()!! > sTime.toEpochSecond())
or ((b.StartTime?.toEpochSecond()!! < eTime.toEpochSecond()) and (b.ETime?.plusMinutes(EndToNextStartMinutes)
?.toEpochSecond()!! > eTime.toEpochSecond()))
or ((b.StartTime?.toEpochSecond()!! > sTime.toEpochSecond()) and (b.ETime?.plusMinutes(EndToNextStartMinutes)
?.toEpochSecond()!! < eTime.toEpochSecond())))
) or (b.EndTime != null && (
(b.StartTime?.toEpochSecond()!! < sTime.toEpochSecond()) and (b.EndTime?.toEpochSecond()!! > sTime.toEpochSecond())
or ((b.StartTime?.toEpochSecond()!! < eTime.toEpochSecond()) and (b.EndTime?.toEpochSecond()!! > eTime.toEpochSecond()))
or ((b.StartTime?.toEpochSecond()!! > sTime.toEpochSecond()) and (b.EndTime?.toEpochSecond()!! < eTime.toEpochSecond())))
)
})
} else {
isAvailable = true
}
updateUiByExistingBookings()
//view?.hideKeyboard()
},
onFailure = {
Log.d("CreateBooking-Fail", it.message.orEmpty())
}
)
}
}
}
private fun getAccessProfile() {
val odt = OffsetDateTime.now()
val zoneOffset = odt.offset
val sTime: OffsetDateTime = OffsetDateTime.of(StartDate, StartTime, zoneOffset)
val eTime: OffsetDateTime = OffsetDateTime.of(StartDate, EndTime, zoneOffset)
CoroutineScope(Dispatchers.IO).launch {
val response =
kotlin.runCatching {
backendApi
.getAccessProfile(
appCommon.getLoginToken(),
appCommon.CurrentChargePoint.Guid.toString()
)
.string()
}
withContext(Dispatchers.Main) {
response.fold(
onSuccess = {
Log.d("checkAvailability-Success", it)
Log.d("checkAvailability-Success", "getAccessProfile: ${it.length}")
var gSon = GsonBuilder()
// .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting()
.registerTypeAdapter(
OffsetDateTime::class.java,
JsonDeserializer { json: JsonElement, type: Type?, context: JsonDeserializationContext? -> OffsetDateTime.parse(json.asString) } as JsonDeserializer<OffsetDateTime>)
.create()
accessProfileList = gSon.fromJson<List<AccessProfile>>(it, listOfAccessProfiles)
accesProfileLoaded = true
if (accessProfileList != null && accessProfileList.count() > 0) {
updateAccessProfileUI()
} else {
}
updateUiByExistingBookings()
//view?.hideKeyboard()
},
onFailure = {
Log.d("CreateBooking-Fail", it.message.orEmpty())
accesProfileLoaded = false
}
)
}
}
}
private fun updateAccessProfileUI() {
if (accesProfileLoaded) {
val dayOfWeek = (2f.pow(StartDate.dayOfWeek.value - 1)).roundToInt()
val todaysProfile = accessProfileList.find { ap -> (ap.Weekday and dayOfWeek) > 0 }
if (todaysProfile != null) {
todaysProfile.calcTimeSlot()
Log.d("Found AccessProfile", todaysProfile.Guid.toString())
var hasRates: Boolean = todaysProfile.hasRates(AccessProfile.Rates.Pv)
// PvTarifLayout.isVisible = hasRates
if (hasRates) {
PvHoursTextView.text = "(" + getTimeFromDuration(todaysProfile.PvStarts) + "-" + getTimeFromDuration(todaysProfile.PvEnds) + ")"
TarifTextView.text = String.format(Locale.GERMAN, "%.0f", appCommon.CurrentChargePoint.MoonShineRate) + " Ct/kWh"
PvTarifTextView.text = String.format(Locale.GERMAN, "%.0f", appCommon.CurrentChargePoint.SunShineRate) + " Ct/kWh"
}
}
}
}
private fun getTimeFromDuration(duration: Duration): String {
val hours: Long = duration.toHours() % 24
val minutes: Long = duration.toMinutes() % 60
return "%02d".format(hours) + "%02d".format(minutes)
}
private val backendApi = BackendApiFactory(baseUrl).create()
private val elementOfBooking = object : TypeToken<Booking?>() {}.type
private fun CreateBooking(booking: Booking) {
CoroutineScope(Dispatchers.IO).launch {
val response =
kotlin.runCatching {
backendApi
.createBooking(
appCommon.getLoginToken(),
booking.CpGuid.toString(),
booking.STime.toString(),
booking.ETime.toString()
)
.string()
}
withContext(Dispatchers.Main) {
response.fold(
onSuccess = {
Log.d("CreateBooking-Success", it)
var gSon = GsonBuilder()
// .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting()
.registerTypeAdapter(
OffsetDateTime::class.java,
JsonDeserializer { json: JsonElement, type: Type?, context: JsonDeserializationContext? -> OffsetDateTime.parse(json.asString) } as JsonDeserializer<OffsetDateTime>)
.create()
var _booking = gSon.fromJson<Booking>(it, elementOfBooking)
if (_booking != null) {
if (appCommon.isAdhocBooking) {
appCommon.setBooking(_booking)
findNavController().navigate(R.id.navigation_charge)
} else {
findNavController().navigate(R.id.navigation_bookings)
}
} else {
}
//view?.hideKeyboard()
},
onFailure = {
Log.d("CreateBooking-Fail", it.message.orEmpty())
}
)
}
}
}
override fun onProgressChanged(p0: SeekBar?, progress: Int, p2: Boolean) {
duration = timeSlots[progress]
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment