mirror of
https://github.com/hmalik144/Weather-apps.git
synced 2025-12-10 02:05:20 +00:00
notification on lower level android working
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
|
||||
<receiver
|
||||
android:name=".service.notification.NotificationReceiver"
|
||||
android:exported="true"/>
|
||||
android:exported="false"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.appttude.h_mal.atlas_weather.application
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.appttude.h_mal.atlas_weather.data.WeatherSource
|
||||
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
|
||||
import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepository
|
||||
import com.appttude.h_mal.atlas_weather.service.notification.NotificationService
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.MainViewModel
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.SettingsViewModel
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||
|
||||
|
||||
class ApplicationViewModelFactory(
|
||||
private val application: Application,
|
||||
private val locationProvider: LocationProvider,
|
||||
private val source: WeatherSource,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val notificationService: NotificationService
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
with(modelClass) {
|
||||
return when {
|
||||
isAssignableFrom(WorldViewModel::class.java) -> WorldViewModel(
|
||||
locationProvider,
|
||||
source
|
||||
)
|
||||
|
||||
isAssignableFrom(MainViewModel::class.java) -> MainViewModel(
|
||||
locationProvider,
|
||||
source
|
||||
)
|
||||
|
||||
isAssignableFrom(SettingsViewModel::class.java) -> SettingsViewModel(
|
||||
application, locationProvider, source, settingsRepository, notificationService
|
||||
)
|
||||
|
||||
else -> throw IllegalArgumentException("Unknown ViewModel class")
|
||||
} as T
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.appttude.h_mal.atlas_weather.service.notification.NotificationHelper
|
||||
import com.appttude.h_mal.atlas_weather.service.notification.NotificationService
|
||||
import org.kodein.di.generic.bind
|
||||
import org.kodein.di.generic.instance
|
||||
import org.kodein.di.generic.provider
|
||||
import org.kodein.di.generic.singleton
|
||||
|
||||
|
||||
@@ -20,12 +21,26 @@ open class AtlasApp : AppClass() {
|
||||
}
|
||||
|
||||
bind() from singleton {
|
||||
NotificationService(this@AtlasApp).let { notificationService = it }
|
||||
NotificationService(this@AtlasApp).apply { notificationService = this }
|
||||
}
|
||||
|
||||
bind() from provider {
|
||||
ApplicationViewModelFactory(
|
||||
this@AtlasApp,
|
||||
instance(),
|
||||
instance(),
|
||||
instance(),
|
||||
instance()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
notificationService.schedulePushNotifications()
|
||||
}
|
||||
// override fun onCreate() {
|
||||
// super.onCreate()
|
||||
// notificationService.schedulePushNotifications()
|
||||
// }
|
||||
|
||||
fun scheduleNotifications() = notificationService.schedulePushNotifications()
|
||||
|
||||
fun unscheduleNotifications() = notificationService.unschedulePushNotifications()
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.appttude.h_mal.atlas_weather.service.notification
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.TaskStackBuilder
|
||||
@@ -10,8 +11,11 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresPermission
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||
@@ -30,9 +34,10 @@ import org.kodein.di.generic.instance
|
||||
* Updated by h_mal on 27/11/2020
|
||||
*/
|
||||
const val NOTIFICATION_CHANNEL_ID = "my_notification_channel_1"
|
||||
|
||||
const val NOTIFICATION_ID = 505
|
||||
class NotificationReceiver : BroadcastReceiver() {
|
||||
|
||||
|
||||
private val kodein = LateInitKodein()
|
||||
private val helper: NotificationHelper by kodein.instance()
|
||||
|
||||
@@ -64,22 +69,51 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
addNextIntent(notificationIntent)
|
||||
}
|
||||
val pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val builder = Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
|
||||
val bmp: Bitmap = runBlocking { Picasso.get().load(weather.current?.icon).get() }
|
||||
|
||||
val notification = builder.setContentTitle("Weather App")
|
||||
.setContentText(weather.current?.main + "°C")
|
||||
.setSmallIcon(R.mipmap.ic_notif) //change icon
|
||||
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
|
||||
.setSmallIcon(R.mipmap.ic_notif)
|
||||
.setLargeIcon(bmp)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent)
|
||||
.build()
|
||||
builder.setChannelId(NOTIFICATION_CHANNEL_ID)
|
||||
.setAutoCancel(true)
|
||||
.setContentTitle("My notification")
|
||||
.setContentText("Much longer text that cannot fit one line...")
|
||||
.setStyle(NotificationCompat.BigTextStyle()
|
||||
.bigText("Much longer text that cannot fit one line..."))
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
|
||||
// Deliver notification
|
||||
val notificationManager =
|
||||
// Create the NotificationChannel, but only on API 26+ because
|
||||
// the NotificationChannel class is not in the Support Library.
|
||||
val name = context.getString(R.string.channel_name)
|
||||
val descriptionText = context.getString(R.string.channel_description)
|
||||
val importance = NotificationManager.IMPORTANCE_DEFAULT
|
||||
val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID, name, importance).apply {
|
||||
description = descriptionText
|
||||
}
|
||||
// Register the channel with the system.
|
||||
val notificationManager: NotificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.notify(0, notification)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
|
||||
with(NotificationManagerCompat.from(context)) {
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.POST_NOTIFICATIONS
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
// TODO: Consider calling
|
||||
// ActivityCompat#requestPermissions
|
||||
// here to request the missing permissions, and then overriding
|
||||
// public fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
|
||||
// grantResults: IntArray)
|
||||
// to handle the case where the user grants the permission. See the documentation
|
||||
// for ActivityCompat#requestPermissions for more details.
|
||||
|
||||
return@with
|
||||
}
|
||||
// notificationId is a unique int for each notification that you must define.
|
||||
notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,8 @@ class NotificationService(context: Context) {
|
||||
AlarmManager.INTERVAL_DAY,
|
||||
alarmPendingIntent
|
||||
)
|
||||
|
||||
// alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(calendar.timeInMillis, alarmPendingIntent), alarmPendingIntent)
|
||||
}
|
||||
|
||||
fun unschedulePushNotifications() {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.appttude.h_mal.atlas_weather.ui.home
|
||||
|
||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
import android.Manifest.permission.POST_NOTIFICATIONS
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
@@ -10,9 +12,8 @@ import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.Navigation.findNavController
|
||||
import androidx.navigation.ui.onNavDestinationSelected
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
||||
import com.appttude.h_mal.atlas_weather.application.AtlasApp
|
||||
import com.appttude.h_mal.atlas_weather.base.BaseFragment
|
||||
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
|
||||
import com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay
|
||||
@@ -56,6 +57,8 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
})
|
||||
|
||||
forecast_listview.adapter = recyclerAdapter
|
||||
|
||||
scheduleNotification()
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@@ -99,6 +102,14 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
onRequestPermissionsResult(requestCode, grantResults)
|
||||
}
|
||||
|
||||
fun scheduleNotification() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
sendNotification()
|
||||
} else {
|
||||
(requireActivity().application as AtlasApp).scheduleNotifications()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@NeedsPermission(ACCESS_COARSE_LOCATION)
|
||||
fun showLocation() {
|
||||
@@ -123,4 +134,29 @@ class HomeFragment : BaseFragment<MainViewModel>(R.layout.fragment_home) {
|
||||
fun onLocationNeverAskAgain() {
|
||||
displayToast("Location permissions have been to never ask again")
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@NeedsPermission(POST_NOTIFICATIONS)
|
||||
fun sendNotification() {
|
||||
(requireActivity().application as AtlasApp).scheduleNotifications()
|
||||
}
|
||||
|
||||
@OnShowRationale(POST_NOTIFICATIONS)
|
||||
fun showRationaleForNotification(request: PermissionRequest) {
|
||||
// PermissionsDeclarationDialog(requireContext()).showDialog({
|
||||
// request.proceed()
|
||||
// }, {
|
||||
// request.cancel()
|
||||
// })
|
||||
}
|
||||
|
||||
@OnPermissionDenied(POST_NOTIFICATIONS)
|
||||
fun onNotificationDenied() {
|
||||
displayToast("Notification permissions have been denied")
|
||||
}
|
||||
|
||||
@OnNeverAskAgain(POST_NOTIFICATIONS)
|
||||
fun onNotificationNeverAskAgain() {
|
||||
displayToast("Notification permissions have been to never ask again")
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,12 @@ import com.appttude.h_mal.atlas_weather.data.repository.RepositoryImpl
|
||||
import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepositoryImpl
|
||||
import com.appttude.h_mal.atlas_weather.data.room.AppDatabase
|
||||
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||
import com.google.gson.Gson
|
||||
import org.kodein.di.Kodein
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.android.x.androidXModule
|
||||
import org.kodein.di.generic.bind
|
||||
import org.kodein.di.generic.instance
|
||||
import org.kodein.di.generic.provider
|
||||
import org.kodein.di.generic.singleton
|
||||
|
||||
abstract class BaseAppClass : Application(), KodeinAware {
|
||||
@@ -40,7 +38,6 @@ abstract class BaseAppClass : Application(), KodeinAware {
|
||||
bind() from singleton { SettingsRepositoryImpl(instance()) }
|
||||
bind() from singleton { ServicesHelper(instance(), instance(), instance()) }
|
||||
bind() from singleton { WeatherSource(instance(), instance()) }
|
||||
bind() from provider { ApplicationViewModelFactory(this@BaseAppClass, instance(), instance(),instance()) }
|
||||
}
|
||||
|
||||
open val flavourModule = Kodein.Module("Flavour") {
|
||||
|
||||
@@ -8,8 +8,6 @@ import com.appttude.h_mal.atlas_weather.data.network.interceptors.QueryParamsInt
|
||||
import com.appttude.h_mal.atlas_weather.data.network.networkUtils.loggingInterceptor
|
||||
import com.appttude.h_mal.atlas_weather.data.room.AppDatabase
|
||||
|
||||
const val LOCATION_PERMISSION_REQUEST = 505
|
||||
|
||||
open class AppClass : BaseAppClass() {
|
||||
|
||||
override fun createNetworkModule(): WeatherApi {
|
||||
|
||||
@@ -8,7 +8,7 @@ import androidx.fragment.app.createViewModelLazy
|
||||
import com.appttude.h_mal.atlas_weather.base.baseViewModels.BaseViewModel
|
||||
import com.appttude.h_mal.atlas_weather.helper.GenericsHelper.getGenericClassAt
|
||||
import com.appttude.h_mal.atlas_weather.model.ViewState
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||
import com.appttude.h_mal.atlas_weather.application.ApplicationViewModelFactory
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.android.x.kodein
|
||||
import org.kodein.di.generic.instance
|
||||
|
||||
@@ -6,11 +6,10 @@ import androidx.annotation.XmlRes
|
||||
import androidx.fragment.app.createViewModelLazy
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.base.baseViewModels.BaseAndroidViewModel
|
||||
import com.appttude.h_mal.atlas_weather.helper.GenericsHelper.getGenericClassAt
|
||||
import com.appttude.h_mal.atlas_weather.model.ViewState
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||
import com.appttude.h_mal.atlas_weather.application.ApplicationViewModelFactory
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.android.x.kodein
|
||||
import org.kodein.di.generic.instance
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
<string name="unit_key">Units</string>
|
||||
<string name="widget_black_background">widget_black_background</string>
|
||||
<string name="weather_units">Weather units</string>
|
||||
<string name="channel_name">channel name</string>
|
||||
<string name="channel_description">channel description</string>
|
||||
|
||||
<string-array name="units">
|
||||
<item>Metric</item>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.appttude.h_mal.atlas_weather.viewmodel
|
||||
package com.appttude.h_mal.atlas_weather.application
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.ViewModel
|
||||
@@ -6,6 +6,9 @@ import androidx.lifecycle.ViewModelProvider
|
||||
import com.appttude.h_mal.atlas_weather.data.WeatherSource
|
||||
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
|
||||
import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepository
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.MainViewModel
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.SettingsViewModel
|
||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||
|
||||
|
||||
class ApplicationViewModelFactory(
|
||||
@@ -1,6 +1,20 @@
|
||||
import com.appttude.h_mal.atlas_weather.application.AppClass
|
||||
import com.appttude.h_mal.atlas_weather.application.ApplicationViewModelFactory
|
||||
import org.kodein.di.generic.bind
|
||||
import org.kodein.di.generic.instance
|
||||
import org.kodein.di.generic.provider
|
||||
import org.kodein.di.generic.singleton
|
||||
|
||||
open class MonoApp : AppClass() {
|
||||
|
||||
override val flavourModule = super.flavourModule.copy {
|
||||
|
||||
bind() from provider {
|
||||
ApplicationViewModelFactory(
|
||||
this@MonoApp,
|
||||
instance(),
|
||||
instance(),
|
||||
instance(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import com.appttude.h_mal.atlas_weather.base.baseViewModels.BaseAndroidViewModel
|
||||
import com.appttude.h_mal.atlas_weather.data.WeatherSource
|
||||
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
|
||||
import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepository
|
||||
import com.appttude.h_mal.atlas_weather.service.notification.NotificationHelper
|
||||
import com.appttude.h_mal.atlas_weather.widget.NewAppWidget
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -24,12 +23,28 @@ class SettingsViewModel(
|
||||
application: Application,
|
||||
private val locationProvider: LocationProvider,
|
||||
private val weatherSource: WeatherSource,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val notificationHelper: NotificationHelper
|
||||
private val settingsRepository: SettingsRepository
|
||||
) : BaseAndroidViewModel(application) {
|
||||
|
||||
private fun getContext() = getApplication<BaseAppClass>().applicationContext
|
||||
|
||||
fun updateWidget() {
|
||||
val context = getContext()
|
||||
val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
|
||||
val widgetManager = AppWidgetManager.getInstance(context)
|
||||
val ids =
|
||||
widgetManager.getAppWidgetIds(
|
||||
ComponentName(
|
||||
context,
|
||||
NewAppWidget::class.java
|
||||
)
|
||||
)
|
||||
AppWidgetManager.getInstance(context)
|
||||
.notifyAppWidgetViewDataChanged(ids, R.id.whole_widget_view)
|
||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
fun refreshWeatherData() {
|
||||
onStart()
|
||||
job = CoroutineScope(Dispatchers.IO).launch {
|
||||
|
||||
Reference in New Issue
Block a user