Kotlin, Android Studio, Unresolved reference 'postNotification'

class BidDetailsDialogFragment(private val bid: Bid) : DialogFragment() {

    private var statusChanged = false
    private var costChanged = false
    private var originalStatus = bid.status
    private var originalEstimatedCost = bid.estimatedCost
    private var originalFinalCost = bid.finalCost

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {

        val view = inflater.inflate(R.layout.dialog_bid_details, container, false)

        // Инициализация всех TextView для отображения информации
        view.findViewById<TextView>(R.id.deviceTextView).text = "Устройство: ${bid.device}"
        view.findViewById<TextView>(R.id.statusTextView).text = "Статус: ${bid.status}"
        view.findViewById<TextView>(R.id.clientNameTextView).text = "Клиент: ${bid.clientName}"
        view.findViewById<TextView>(R.id.clientEmailTextView).text = "Email: ${bid.clientEmail}"
        view.findViewById<TextView>(R.id.descriptionTextView).text = "Описание: ${bid.description}"
        view.findViewById<TextView>(R.id.creationDateTextView).text = "Дата создания: ${bid.creationDate}"
        view.findViewById<TextView>(R.id.phoneNumberTextView).text = "Телефон: ${bid.phoneNumber}"

        // Инициализация EditText для стоимости
        val estimatedCostEditText = view.findViewById<EditText>(R.id.estimatedCostEditText)
        val finalCostEditText = view.findViewById<EditText>(R.id.finalCostEditText)

        // Инициализация Spinner для изменения статуса
        val statusSpinner = view.findViewById<Spinner>(R.id.statusSpinner)
        val statuses = arrayOf("Открыта", "Диагностика", "В работе", "Ожидает получения", "Закрыта")
        val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, statuses)
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        statusSpinner.adapter = adapter
        statusSpinner.setSelection(statuses.indexOf(bid.status))

        // Установка текущих значений стоимости
        bid.estimatedCost?.let {
            estimatedCostEditText.setText(it.toString())
        }
        bid.finalCost?.let {
            finalCostEditText.setText(it.toString())
        }

        // Логика отображения полей стоимости в зависимости от статуса
        updateCostFieldsVisibility(bid.status, estimatedCostEditText, finalCostEditText)

        // Обработчик изменения статуса
        statusSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
                val newStatus = statuses[position]
                statusChanged = newStatus != originalStatus
                updateCostFieldsVisibility(newStatus, estimatedCostEditText, finalCostEditText)
            }

            override fun onNothingSelected(parent: AdapterView<*>?) {}
        }

        // Кнопка сохранения
        view.findViewById<Button>(R.id.saveButton).setOnClickListener {
            val newStatus = statusSpinner.selectedItem.toString()
            val estimatedCostStr = estimatedCostEditText.text.toString()
            val finalCostStr = finalCostEditText.text.toString()

            // Проверка изменения в стоимости
            costChanged = when (newStatus) {
                "Открыта", "Диагностика", "В работе" -> {
                    estimatedCostStr.toDoubleOrNull() != originalEstimatedCost
                }
                "Ожидает получения", "Закрыта" -> {
                    finalCostStr.toDoubleOrNull() != originalFinalCost
                }
                else -> false
            }

            saveChanges(newStatus, estimatedCostStr, finalCostStr)
        }

        // Кнопка отмены
        view.findViewById<Button>(R.id.cancelButton).setOnClickListener {
            dismiss()
        }

        return view
    }

    private fun updateCostFieldsVisibility(
        status: String,
        estimatedCostEditText: EditText,
        finalCostEditText: EditText
    ) {
        when (status) {
            "Открыта", "Диагностика", "В работе" -> {
                estimatedCostEditText.visibility = View.VISIBLE
                finalCostEditText.visibility = View.GONE
            }
            "Ожидает получения", "Закрыта" -> {
                estimatedCostEditText.visibility = View.GONE
                finalCostEditText.visibility = View.VISIBLE
            }
            else -> {
                estimatedCostEditText.visibility = View.GONE
                finalCostEditText.visibility = View.GONE
            }
        }
    }

    private fun saveChanges(newStatus: String, estimatedCostStr: String, finalCostStr: String) {
        val database = Firebase.database.reference
        val updates = hashMapOf<String, Any>(
            "status" to newStatus
        )

        // Добавление стоимость в зависимости от статуса
        when (newStatus) {
            "Открыта", "Диагностика", "В работе" -> {
                estimatedCostStr.toDoubleOrNull()?.let {
                    updates["estimatedCost"] = it
                }
            }
            "Ожидает получения", "Закрыта" -> {
                finalCostStr.toDoubleOrNull()?.let {
                    updates["finalCost"] = it
                }
            }
        }

        database.child("bids").child(bid.id).updateChildren(updates)
            .addOnSuccessListener {
                Toast.makeText(requireContext(), "Изменения сохранены", Toast.LENGTH_SHORT).show()

                // Отправляем уведомление, если были изменения статуса или стоимости
                if (statusChanged || costChanged) {
                    sendNotificationToClient(newStatus, estimatedCostStr, finalCostStr)
                }

                dismiss()
            }
            .addOnFailureListener {
                Toast.makeText(requireContext(), "Ошибка при сохранении", Toast.LENGTH_SHORT).show()
            }
    }

    private fun sendNotificationToClient(newStatus: String, estimatedCostStr: String, finalCostStr: String) {
        // Создаем текст уведомления в зависимости от изменений
        val notificationMessage = buildString {
            append("Статус вашей заявки на ремонт ")
            append(bid.device)

            if (statusChanged) {
                append(" изменен на \"$newStatus\"")
            }

            if (costChanged) {
                if (statusChanged) append(" и ") else append(": ")

                when (newStatus) {
                    "Открыта", "Диагностика", "В работе" -> {
                        estimatedCostStr.toDoubleOrNull()?.let {
                            append("предварительная стоимость: $it руб.")
                        }
                    }
                    "Ожидает получения", "Закрыта" -> {
                        finalCostStr.toDoubleOrNull()?.let {
                            append("итоговая стоимость: $it руб.")
                        }
                    }
                }
            }

            append(". Подробности в приложении.")
        }

        // Создание тега для OneSignal (исп. email клиента как идентификатор)
        val emailTag = bid.clientEmail.replace("[^a-zA-Z0-9]".toRegex(), "_")

        // Отправка уведомления через OneSignal
        val notification = JSONObject()
        notification.put("app_id", "my_app_id") // Replace with your OneSignal App ID
        notification.put("contents", JSONObject().put("en", notificationMessage))
        notification.put("include_email_tokens", JSONArray().put(bid.clientEmail))
        notification.put("filters", JSONArray().put(JSONObject().put("field", "tag").put("key", "email").put("relation", "=").put("value", emailTag)))
        notification.put("headings", JSONObject().put("en", "Обновление по заявке №${bid.id}"))

        OneSignal.postNotification(notification, null)
    }

}

Зависимость добавлена implementation("com.onesignal:OneSignal:[5.1.32]"), но не видит OneSignal.postNotification вообще никак, кэш чистил, обновлял все, что можно было, ничего не помогает как будто.


Ответы (0 шт):