mirror of
https://github.com/hmalik144/Weather-apps.git
synced 2025-12-10 02:05:20 +00:00
Wake screen widget (#8)
* - Update widget validation * - Cleaned widget folder and code
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
/.idea/caches
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
|
||||
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
@@ -29,7 +29,7 @@ class ServicesHelper(
|
||||
private val repository: Repository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val locationProvider: LocationProvider
|
||||
){
|
||||
) {
|
||||
|
||||
@RequiresPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||
suspend fun fetchData(): Boolean {
|
||||
@@ -60,13 +60,14 @@ class ServicesHelper(
|
||||
suspend fun getWidgetWeather(): WidgetData? {
|
||||
return try {
|
||||
val result = repository.loadSingleCurrentWeatherFromRoom(CURRENT_LOCATION)
|
||||
|
||||
val epoc = System.currentTimeMillis()
|
||||
|
||||
result.weather.let {
|
||||
val bitmap = it.current?.icon
|
||||
val location = locationProvider.getLocationNameFromLatLong(it.lat, it.lon)
|
||||
val temp = it.current?.temp?.toInt().toString()
|
||||
|
||||
WidgetData(location, bitmap, temp)
|
||||
WidgetData(location, bitmap, temp, epoc)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
@@ -80,7 +81,7 @@ class ServicesHelper(
|
||||
|
||||
result.weather.daily?.drop(1)?.dropLast(2)?.forEach { dailyWeather ->
|
||||
val day = dailyWeather.dt?.toSmallDayName()
|
||||
val bitmap = withContext(Dispatchers.Main) {
|
||||
val bitmap = withContext(Dispatchers.Main) {
|
||||
getBitmapFromUrl(dailyWeather.icon)
|
||||
}
|
||||
val temp = dailyWeather.max?.toInt().toString()
|
||||
@@ -102,15 +103,16 @@ class ServicesHelper(
|
||||
val bitmap = it.current?.icon
|
||||
val location = locationProvider.getLocationNameFromLatLong(it.lat, it.lon)
|
||||
val temp = it.current?.temp?.toInt().toString()
|
||||
val epoc = System.currentTimeMillis()
|
||||
|
||||
WidgetData(location, bitmap, temp)
|
||||
WidgetData(location, bitmap, temp, epoc)
|
||||
}
|
||||
|
||||
val list = mutableListOf<InnerWidgetCellData>()
|
||||
|
||||
result.weather.daily?.drop(1)?.dropLast(2)?.forEach { dailyWeather ->
|
||||
val day = dailyWeather.dt?.toSmallDayName()
|
||||
val icon = dailyWeather.icon
|
||||
val icon = dailyWeather.icon
|
||||
val temp = dailyWeather.max?.toInt().toString()
|
||||
|
||||
val item = InnerWidgetCellData(day, icon, temp)
|
||||
@@ -126,25 +128,24 @@ class ServicesHelper(
|
||||
|
||||
private suspend fun getBitmapFromUrl(imageAddress: String?): Bitmap? {
|
||||
return suspendCoroutine { cont ->
|
||||
Picasso.get().load(imageAddress).into(object : Target {
|
||||
override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) {
|
||||
cont.resume(bitmap)
|
||||
}
|
||||
Picasso.get().load(imageAddress).into(object : Target {
|
||||
override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) {
|
||||
cont.resume(bitmap)
|
||||
}
|
||||
|
||||
override fun onBitmapFailed(e: Exception?, d: Drawable?) {
|
||||
cont.resume(null)
|
||||
}
|
||||
override fun onBitmapFailed(e: Exception?, d: Drawable?) {
|
||||
cont.resume(null)
|
||||
}
|
||||
|
||||
override fun onPrepareLoad(placeHolderDrawable: Drawable?) {}
|
||||
})
|
||||
override fun onPrepareLoad(placeHolderDrawable: Drawable?) {}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun getWidgetBackground(): Int {
|
||||
return if (settingsRepository.isBlackBackground()) {
|
||||
return if (settingsRepository.isBlackBackground())
|
||||
Color.BLACK
|
||||
} else {
|
||||
else
|
||||
Color.TRANSPARENT
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,8 @@ import android.graphics.Bitmap
|
||||
data class WidgetData(
|
||||
val location: String?,
|
||||
val icon: String?,
|
||||
val currentTemp: String?
|
||||
val currentTemp: String?,
|
||||
val timeStamp: Long
|
||||
)
|
||||
|
||||
data class InnerWidgetData(
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
android:rowCount="1">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/widget_item_0"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
@@ -165,6 +166,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/widget_item_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
@@ -197,6 +199,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/widget_item_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
@@ -229,6 +232,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/widget_item_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
@@ -260,6 +264,7 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/widget_item_4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
|
||||
@@ -5,42 +5,48 @@ import android.app.PendingIntent
|
||||
import android.app.TaskStackBuilder
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViews
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.core.app.JobIntentService
|
||||
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.LateInitKodein
|
||||
import org.kodein.di.generic.instance
|
||||
|
||||
abstract class BaseWidgetServiceIntentClass : JobIntentService(){
|
||||
abstract class BaseWidgetServiceIntentClass<T: AppWidgetProvider> : JobIntentService(){
|
||||
|
||||
private val kodein = LateInitKodein()
|
||||
val helper: ServicesHelper by kodein.instance()
|
||||
lateinit var appWidgetManager: AppWidgetManager
|
||||
lateinit var appWidgetIds: IntArray
|
||||
|
||||
fun setKodein(context: Context){
|
||||
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
|
||||
fun initBaseWidget(componentName: ComponentName){
|
||||
appWidgetManager = AppWidgetManager.getInstance(baseContext)
|
||||
appWidgetIds = appWidgetManager.getAppWidgetIds(componentName)
|
||||
}
|
||||
|
||||
fun createRemoteView(context: Context, @LayoutRes id: Int): RemoteViews {
|
||||
return RemoteViews(context.packageName, id)
|
||||
fun createRemoteView(@LayoutRes id: Int): RemoteViews {
|
||||
return RemoteViews(packageName, id)
|
||||
}
|
||||
|
||||
// Create pending intent commonly used for 'click to update' features
|
||||
fun <T: AppWidgetProvider> createUpdatePendingIntent(
|
||||
fun createUpdatePendingIntent(
|
||||
appWidgetProvider: Class<T>,
|
||||
context: Context,
|
||||
appWidgetId: Int
|
||||
): PendingIntent? {
|
||||
val seconds = (System.currentTimeMillis() / 1000L).toInt()
|
||||
val intentUpdate = Intent(context.applicationContext, appWidgetProvider)
|
||||
val intentUpdate = Intent(applicationContext, appWidgetProvider)
|
||||
intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
val idArray = intArrayOf(appWidgetId)
|
||||
intentUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, idArray)
|
||||
return PendingIntent.getBroadcast(
|
||||
context, seconds, intentUpdate,
|
||||
this, seconds, intentUpdate,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
@@ -48,11 +54,26 @@ abstract class BaseWidgetServiceIntentClass : JobIntentService(){
|
||||
* create a pending intent used to navigate to activity:
|
||||
* @param activityClass
|
||||
*/
|
||||
fun <T: Activity> createClickingPendingIntent(context: Context, activityClass: Class<T>): PendingIntent {
|
||||
val clickIntentTemplate = Intent(context, activityClass)
|
||||
fun <T: Activity> createClickingPendingIntent(activityClass: Class<T>): PendingIntent {
|
||||
val clickIntentTemplate = Intent(this, activityClass)
|
||||
|
||||
return TaskStackBuilder.create(context)
|
||||
return TaskStackBuilder.create(this)
|
||||
.addNextIntentWithParentStack(clickIntentTemplate)
|
||||
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
|
||||
fun setImageView(
|
||||
path: String?,
|
||||
views: RemoteViews,
|
||||
@IdRes viewId: Int,
|
||||
appWidgetId: Int
|
||||
){
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
Picasso.get().load(path).into(views, viewId, intArrayOf(appWidgetId))
|
||||
}
|
||||
}
|
||||
|
||||
open fun bindView(widgetId: Int, views: RemoteViews, data: Any?) {}
|
||||
open fun bindEmptyView(widgetId: Int, views: RemoteViews, data: Any?) {}
|
||||
open fun bindErrorView(widgetId: Int, views: RemoteViews, data: Any?) {}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViews
|
||||
import android.widget.RemoteViewsService.RemoteViewsFactory
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
||||
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetData
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.android.kodein
|
||||
import org.kodein.di.generic.instance
|
||||
|
||||
|
||||
class MyWidgetRemoteViewsFactory(
|
||||
private val context: Context,
|
||||
val intent: Intent
|
||||
) : RemoteViewsFactory, KodeinAware{
|
||||
|
||||
override val kodein by kodein(context)
|
||||
private val helper : ServicesHelper by kodein.instance()
|
||||
|
||||
private var list: List<InnerWidgetData>? = null
|
||||
|
||||
override fun onCreate() {}
|
||||
override fun onDataSetChanged() {
|
||||
runBlocking {
|
||||
list = helper.getWidgetInnerWeather()
|
||||
}
|
||||
}
|
||||
override fun onDestroy() {}
|
||||
|
||||
override fun getCount(): Int = list?.size ?: 5
|
||||
|
||||
override fun getViewAt(i: Int): RemoteViews {
|
||||
val rv = RemoteViews(context.packageName, R.layout.widget_item)
|
||||
if (list.isNullOrEmpty()) return rv
|
||||
|
||||
list?.get(i)?.let {
|
||||
rv.setTextViewText(R.id.widget_item_day, it.date)
|
||||
rv.setImageViewBitmap(R.id.widget_item_image, it.icon)
|
||||
rv.setTextViewText(R.id.widget_item_temp_high, it.highTemp)
|
||||
rv.setOnClickFillInIntent(R.id.widget_item_layout, intent)
|
||||
}
|
||||
|
||||
return rv
|
||||
}
|
||||
|
||||
override fun getLoadingView(): RemoteViews {
|
||||
return RemoteViews(context.packageName, R.layout.widget_item_loading)
|
||||
}
|
||||
|
||||
override fun getViewTypeCount(): Int = 2
|
||||
|
||||
override fun getItemId(i: Int): Long = i.toLong()
|
||||
|
||||
override fun hasStableIds(): Boolean = true
|
||||
|
||||
}
|
||||
@@ -3,187 +3,178 @@ package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
import android.net.Uri
|
||||
import android.icu.text.SimpleDateFormat
|
||||
import android.os.PowerManager
|
||||
import android.widget.RemoteViews
|
||||
import android.os.Build
|
||||
import androidx.core.app.ActivityCompat.checkSelfPermission
|
||||
import com.appttude.h_mal.atlas_weather.R
|
||||
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper
|
||||
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetCellData
|
||||
import com.appttude.h_mal.atlas_weather.model.widget.WidgetWeatherCollection
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.ui.MainActivity
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetState.*
|
||||
import com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetState.Companion.getWidgetState
|
||||
import com.appttude.h_mal.atlas_weather.utils.isInternetAvailable
|
||||
import com.appttude.h_mal.atlas_weather.utils.tryOrNullSuspended
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.LateInitKodein
|
||||
import org.kodein.di.generic.instance
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* Example implementation of a JobIntentService.
|
||||
* Implementation of a JobIntentService used for home screen widget
|
||||
*/
|
||||
class WidgetJobServiceIntent : BaseWidgetServiceIntentClass() {
|
||||
const val HALF_DAY = 43200000L
|
||||
class WidgetJobServiceIntent : BaseWidgetServiceIntentClass<NewAppWidget>() {
|
||||
|
||||
private val kodein = LateInitKodein()
|
||||
private val helper: ServicesHelper by kodein.instance()
|
||||
|
||||
override fun onHandleWork(intent: Intent) {
|
||||
// We have received work to do. The system or framework is already
|
||||
// holding a wake lock for us at this point, so we can just go.
|
||||
|
||||
executeWidgetUpdate()
|
||||
kodein.baseKodein = (applicationContext as KodeinAware).kodein
|
||||
executeWidgetUpdate()
|
||||
}
|
||||
|
||||
private fun executeWidgetUpdate(){
|
||||
setKodein(this)
|
||||
private fun executeWidgetUpdate() {
|
||||
val componentName = ComponentName(this, NewAppWidget::class.java)
|
||||
initBaseWidget(componentName)
|
||||
|
||||
val appWidgetManager = AppWidgetManager.getInstance(this)
|
||||
val thisAppWidget = ComponentName(packageName, NewAppWidget::class.java.name)
|
||||
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
|
||||
initiateWidgetUpdate(getCurrentWidgetState())
|
||||
}
|
||||
|
||||
validateOperation()?.let {
|
||||
if (it) updateWidget(appWidgetIds, appWidgetManager)
|
||||
else updateErrorWidget(appWidgetIds, appWidgetManager)
|
||||
private fun initiateWidgetUpdate(state: WidgetState) {
|
||||
when (state) {
|
||||
NO_LOCATION, SCREEN_ON_CONNECTION_UNAVAILABLE -> updateErrorWidget(state)
|
||||
SCREEN_ON_CONNECTION_AVAILABLE -> updateWidget(false)
|
||||
SCREEN_OFF_CONNECTION_AVAILABLE -> updateWidget(true)
|
||||
SCREEN_OFF_CONNECTION_UNAVAILABLE -> return
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateWidget(appWidgetIds: IntArray, appWidgetManager: AppWidgetManager){
|
||||
private fun updateWidget(fromStorage: Boolean) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val result = getWidgetWeather()
|
||||
|
||||
for (appWidgetId in appWidgetIds) {
|
||||
bindView(this@WidgetJobServiceIntent, appWidgetManager, appWidgetId, result)
|
||||
}
|
||||
val result = getWidgetWeather(fromStorage)
|
||||
appWidgetIds.forEach { id -> setupView(id, result) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateErrorWidget(appWidgetIds: IntArray, appWidgetManager: AppWidgetManager){
|
||||
for (appWidgetId in appWidgetIds) {
|
||||
setEmptyView(this, appWidgetManager, appWidgetId)
|
||||
}
|
||||
private fun updateErrorWidget(state: WidgetState) {
|
||||
appWidgetIds.forEach { id -> setEmptyView(id, state) }
|
||||
}
|
||||
|
||||
private fun validateOperation(): Boolean? {
|
||||
private fun getCurrentWidgetState(): WidgetState {
|
||||
val pm = getSystemService(POWER_SERVICE) as PowerManager
|
||||
val isScreenOn = pm.isInteractive
|
||||
val locationGranted =
|
||||
checkSelfPermission(this, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
|
||||
val internetAvailable = isInternetAvailable(this.applicationContext)
|
||||
|
||||
// no location return false
|
||||
if (!locationGranted) return false
|
||||
// internet is available lets go
|
||||
if (internetAvailable) return true
|
||||
// screen is off and no connection, do nothing
|
||||
if (!isScreenOn && !internetAvailable) return null
|
||||
|
||||
return if (isScreenOn && !internetAvailable) false else null
|
||||
}
|
||||
|
||||
private fun createForecastListIntent(
|
||||
context: Context,
|
||||
appWidgetId: Int
|
||||
): Intent {
|
||||
return Intent(context, WidgetRemoteViewsService::class.java).apply {
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
|
||||
}
|
||||
return getWidgetState(locationGranted, isScreenOn, internetAvailable)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
suspend fun getWidgetWeather(): WidgetWeatherCollection? {
|
||||
suspend fun getWidgetWeather(storageOnly: Boolean): WidgetWeatherCollection? {
|
||||
return tryOrNullSuspended {
|
||||
helper.fetchData()
|
||||
if (!storageOnly) helper.fetchData()
|
||||
helper.getWidgetWeatherCollection()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setEmptyView(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
|
||||
try {
|
||||
val error = if (checkSelfPermission(context, ACCESS_COARSE_LOCATION)
|
||||
!= PERMISSION_GRANTED) {
|
||||
"No Permission"
|
||||
} else if (!isInternetAvailable(context.applicationContext)) {
|
||||
"No Connection"
|
||||
} else {
|
||||
"No Data"
|
||||
}
|
||||
val updatePendingIntent = createUpdatePendingIntent(NewAppWidget::class.java, context, appWidgetId)
|
||||
val views = createRemoteView(context, R.layout.weather_app_widget)
|
||||
bindEmptyView(appWidgetManager, appWidgetId, views, updatePendingIntent, error)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
private fun setEmptyView(appWidgetId: Int, state: WidgetState) {
|
||||
val error = when (state) {
|
||||
NO_LOCATION -> "No Location Permission"
|
||||
SCREEN_ON_CONNECTION_UNAVAILABLE -> "No network available"
|
||||
else -> "No data"
|
||||
}
|
||||
|
||||
val views = createRemoteView(R.layout.weather_app_widget)
|
||||
bindErrorView(appWidgetId, views, error)
|
||||
}
|
||||
|
||||
private fun bindEmptyView(
|
||||
appWidgetManager: AppWidgetManager,
|
||||
private fun setupView(
|
||||
appWidgetId: Int,
|
||||
views: RemoteViews,
|
||||
clickingUpdateIntent: PendingIntent?,
|
||||
warning: String
|
||||
collection: WidgetWeatherCollection?
|
||||
) {
|
||||
setLastUpdated(views)
|
||||
views.setTextViewText(R.id.widget_current_location, warning)
|
||||
views.setImageViewResource(R.id.widget_current_icon, R.drawable.ic_baseline_cloud_off_24)
|
||||
views.setImageViewResource(R.id.location_icon, 0)
|
||||
|
||||
views.setTextViewText(R.id.widget_main_temp, "")
|
||||
views.setTextViewText(R.id.widget_feel_temp, "")
|
||||
|
||||
views.setOnClickPendingIntent(R.id.widget_current_icon, clickingUpdateIntent)
|
||||
views.setOnClickPendingIntent(R.id.widget_current_location, clickingUpdateIntent)
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
|
||||
}
|
||||
|
||||
private fun bindView(
|
||||
context: Context,
|
||||
appWidgetManager: AppWidgetManager,
|
||||
appWidgetId: Int,
|
||||
collection: WidgetWeatherCollection?) {
|
||||
val views = createRemoteView(context, R.layout.weather_app_widget)
|
||||
setLastUpdated(views)
|
||||
val views = createRemoteView(R.layout.weather_app_widget)
|
||||
setLastUpdated(views, collection?.widgetData?.timeStamp)
|
||||
views.setInt(R.id.whole_widget_view, "setBackgroundColor", helper.getWidgetBackground())
|
||||
val clickingUpdatePendingIntent = createUpdatePendingIntent(NewAppWidget::class.java, context, appWidgetId)
|
||||
|
||||
if (collection != null) {
|
||||
val clickPendingIntentTemplate =
|
||||
createClickingPendingIntent(context, MainActivity::class.java)
|
||||
|
||||
views.apply {
|
||||
val weather = collection.widgetData
|
||||
|
||||
setTextViewText(R.id.widget_main_temp, weather.currentTemp)
|
||||
setTextViewText(R.id.widget_feel_temp, "°C")
|
||||
setTextViewText(R.id.widget_current_location, weather.location)
|
||||
setImageViewResource(R.id.location_icon, R.drawable.location_flag)
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
Picasso.get().load(weather.icon).into(views, R.id.widget_current_icon, intArrayOf(appWidgetId))
|
||||
}
|
||||
setPendingIntentTemplate(R.id.widget_listview, clickPendingIntentTemplate)
|
||||
setOnClickPendingIntent(R.id.widget_current_icon, clickingUpdatePendingIntent)
|
||||
setOnClickPendingIntent(R.id.widget_current_location, clickingUpdatePendingIntent)
|
||||
|
||||
loadCells(appWidgetId, views, collection.forecast)
|
||||
// setRemoteAdapter(R.id.widget_listview, forecastListIntent)
|
||||
}
|
||||
|
||||
// Instruct the widget manager to update the widget
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview)
|
||||
bindView(appWidgetId, views, collection)
|
||||
} else {
|
||||
bindEmptyView(appWidgetManager, appWidgetId, views, clickingUpdatePendingIntent, "No Connection")
|
||||
bindEmptyView(appWidgetId, views, "No weather available")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun loadCells(appWidgetId: Int, remoteViews: RemoteViews, weather: List<InnerWidgetCellData>){
|
||||
override fun bindErrorView(
|
||||
widgetId: Int,
|
||||
views: RemoteViews,
|
||||
data: Any?
|
||||
) {
|
||||
bindEmptyView(widgetId, views, data)
|
||||
}
|
||||
|
||||
override fun bindEmptyView(
|
||||
widgetId: Int,
|
||||
views: RemoteViews,
|
||||
data: Any?
|
||||
) {
|
||||
val clickUpdate = createUpdatePendingIntent(NewAppWidget::class.java, widgetId)
|
||||
|
||||
views.apply {
|
||||
setTextViewText(R.id.widget_current_location, data as String)
|
||||
setImageViewResource(R.id.widget_current_icon, R.drawable.ic_baseline_cloud_off_24)
|
||||
setImageViewResource(R.id.location_icon, 0)
|
||||
|
||||
setTextViewText(R.id.widget_main_temp, "")
|
||||
setTextViewText(R.id.widget_feel_temp, "")
|
||||
|
||||
setOnClickPendingIntent(R.id.widget_current_icon, clickUpdate)
|
||||
setOnClickPendingIntent(R.id.widget_current_location, clickUpdate)
|
||||
appWidgetManager.updateAppWidget(widgetId, this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindView(widgetId: Int, views: RemoteViews, data: Any?) {
|
||||
val clickUpdate = createUpdatePendingIntent(NewAppWidget::class.java, widgetId)
|
||||
val clickToMain = createClickingPendingIntent(MainActivity::class.java)
|
||||
|
||||
val collection = data as WidgetWeatherCollection
|
||||
val weather = collection.widgetData
|
||||
views.apply {
|
||||
setTextViewText(R.id.widget_main_temp, weather.currentTemp)
|
||||
setTextViewText(R.id.widget_feel_temp, "°C")
|
||||
setTextViewText(R.id.widget_current_location, weather.location)
|
||||
setImageViewResource(R.id.location_icon, R.drawable.location_flag)
|
||||
setImageView(weather.icon, this, R.id.widget_current_icon, widgetId)
|
||||
setOnClickPendingIntent(R.id.widget_current_icon, clickUpdate)
|
||||
setOnClickPendingIntent(R.id.widget_current_location, clickUpdate)
|
||||
|
||||
loadCells(widgetId, this, collection.forecast, clickToMain)
|
||||
// Instruct the widget manager to update the widget
|
||||
appWidgetManager.updateAppWidget(widgetId, views)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadCells(
|
||||
appWidgetId: Int,
|
||||
remoteViews: RemoteViews,
|
||||
weather: List<InnerWidgetCellData>,
|
||||
clickIntent: PendingIntent
|
||||
) {
|
||||
(0..4).forEach { i ->
|
||||
val containerId: Int = resources.getIdentifier("widget_item_$i", "id", packageName)
|
||||
val dayId: Int = resources.getIdentifier("widget_item_day_$i", "id", packageName)
|
||||
val imageId: Int = resources.getIdentifier("widget_item_image_$i", "id", packageName)
|
||||
val tempId: Int = resources.getIdentifier("widget_item_temp_high_$i", "id", packageName)
|
||||
@@ -192,18 +183,24 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass() {
|
||||
|
||||
remoteViews.setTextViewText(dayId, it.date)
|
||||
remoteViews.setTextViewText(tempId, it.highTemp)
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
Picasso.get().load(it.icon).into(remoteViews, imageId, intArrayOf(appWidgetId))
|
||||
}
|
||||
setImageView(it.icon, remoteViews, imageId, appWidgetId)
|
||||
remoteViews.setOnClickPendingIntent(containerId, clickIntent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLastUpdated(views: RemoteViews){
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
val current = LocalDateTime.now()
|
||||
val formatter = DateTimeFormatter.ofPattern("HH:mm")
|
||||
val formatted = current.format(formatter)
|
||||
views.setTextViewText(R.id.widget_current_status, "last updated: $formatted")
|
||||
private fun setLastUpdated(views: RemoteViews, timeStamp: Long?) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && timeStamp != null) {
|
||||
val difference = System.currentTimeMillis().minus(timeStamp)
|
||||
|
||||
val status = if (difference > HALF_DAY) {
|
||||
"12hrs ago"
|
||||
} else {
|
||||
val date = Date(timeStamp)
|
||||
val sdf = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||
sdf.format(date)
|
||||
}
|
||||
|
||||
views.setTextViewText(R.id.widget_current_status, "last updated: $status")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
||||
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViewsService
|
||||
|
||||
class WidgetRemoteViewsService : RemoteViewsService() {
|
||||
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
||||
return MyWidgetRemoteViewsFactory(applicationContext, intent)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
||||
|
||||
enum class WidgetState {
|
||||
NO_LOCATION,
|
||||
SCREEN_ON_CONNECTION_AVAILABLE,
|
||||
SCREEN_ON_CONNECTION_UNAVAILABLE,
|
||||
SCREEN_OFF_CONNECTION_AVAILABLE,
|
||||
SCREEN_OFF_CONNECTION_UNAVAILABLE;
|
||||
|
||||
companion object {
|
||||
fun getWidgetState(
|
||||
locationAvailable: Boolean,
|
||||
screenOn: Boolean,
|
||||
connectionAvailable: Boolean
|
||||
): WidgetState {
|
||||
return if (!locationAvailable)
|
||||
NO_LOCATION
|
||||
else if (screenOn && connectionAvailable)
|
||||
SCREEN_ON_CONNECTION_AVAILABLE
|
||||
else if (screenOn && !connectionAvailable)
|
||||
SCREEN_ON_CONNECTION_UNAVAILABLE
|
||||
else if (!screenOn && connectionAvailable)
|
||||
SCREEN_OFF_CONNECTION_AVAILABLE
|
||||
else
|
||||
SCREEN_OFF_CONNECTION_UNAVAILABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.appttude.h_mal.atlas_weather.monoWeather.widget
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.app.TaskStackBuilder
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
fun <T: Activity> createClickingPendingIntent(context: Context, activityClass: Class<T>): PendingIntent {
|
||||
val clickIntentTemplate = Intent(context, activityClass)
|
||||
|
||||
return TaskStackBuilder.create(context)
|
||||
.addNextIntentWithParentStack(clickIntentTemplate)
|
||||
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
Reference in New Issue
Block a user