Wake screen widget (#8)

* - Update widget validation
* - Cleaned widget folder and code
This commit is contained in:
2022-02-15 00:57:52 +00:00
committed by GitHub
parent ed78d40cc0
commit a1a32e4ceb
11 changed files with 213 additions and 244 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
/local.properties /local.properties
/.idea/workspace.xml /.idea/workspace.xml
/.idea/libraries /.idea/libraries
/.idea/caches
.DS_Store .DS_Store
/build /build
/captures /captures

Binary file not shown.

View File

@@ -60,13 +60,14 @@ class ServicesHelper(
suspend fun getWidgetWeather(): WidgetData? { suspend fun getWidgetWeather(): WidgetData? {
return try { return try {
val result = repository.loadSingleCurrentWeatherFromRoom(CURRENT_LOCATION) val result = repository.loadSingleCurrentWeatherFromRoom(CURRENT_LOCATION)
val epoc = System.currentTimeMillis()
result.weather.let { result.weather.let {
val bitmap = it.current?.icon val bitmap = it.current?.icon
val location = locationProvider.getLocationNameFromLatLong(it.lat, it.lon) val location = locationProvider.getLocationNameFromLatLong(it.lat, it.lon)
val temp = it.current?.temp?.toInt().toString() val temp = it.current?.temp?.toInt().toString()
WidgetData(location, bitmap, temp) WidgetData(location, bitmap, temp, epoc)
} }
} catch (e: Exception) { } catch (e: Exception) {
null null
@@ -102,8 +103,9 @@ class ServicesHelper(
val bitmap = it.current?.icon val bitmap = it.current?.icon
val location = locationProvider.getLocationNameFromLatLong(it.lat, it.lon) val location = locationProvider.getLocationNameFromLatLong(it.lat, it.lon)
val temp = it.current?.temp?.toInt().toString() val temp = it.current?.temp?.toInt().toString()
val epoc = System.currentTimeMillis()
WidgetData(location, bitmap, temp) WidgetData(location, bitmap, temp, epoc)
} }
val list = mutableListOf<InnerWidgetCellData>() val list = mutableListOf<InnerWidgetCellData>()
@@ -141,10 +143,9 @@ class ServicesHelper(
} }
fun getWidgetBackground(): Int { fun getWidgetBackground(): Int {
return if (settingsRepository.isBlackBackground()) { return if (settingsRepository.isBlackBackground())
Color.BLACK Color.BLACK
} else { else
Color.TRANSPARENT Color.TRANSPARENT
} }
} }
}

View File

@@ -5,7 +5,8 @@ import android.graphics.Bitmap
data class WidgetData( data class WidgetData(
val location: String?, val location: String?,
val icon: String?, val icon: String?,
val currentTemp: String? val currentTemp: String?,
val timeStamp: Long
) )
data class InnerWidgetData( data class InnerWidgetData(

View File

@@ -133,6 +133,7 @@
android:rowCount="1"> android:rowCount="1">
<LinearLayout <LinearLayout
android:id="@+id/widget_item_0"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_columnWeight="1" android:layout_columnWeight="1"
@@ -165,6 +166,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/widget_item_1"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_columnWeight="1" android:layout_columnWeight="1"
@@ -197,6 +199,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/widget_item_2"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_columnWeight="1" android:layout_columnWeight="1"
@@ -229,6 +232,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/widget_item_3"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_columnWeight="1" android:layout_columnWeight="1"
@@ -260,6 +264,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/widget_item_4"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_columnWeight="1" android:layout_columnWeight="1"

View File

@@ -5,42 +5,48 @@ import android.app.PendingIntent
import android.app.TaskStackBuilder import android.app.TaskStackBuilder
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.widget.RemoteViews import android.widget.RemoteViews
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.core.app.JobIntentService import androidx.core.app.JobIntentService
import com.appttude.h_mal.atlas_weather.helper.ServicesHelper 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.KodeinAware
import org.kodein.di.LateInitKodein import org.kodein.di.LateInitKodein
import org.kodein.di.generic.instance import org.kodein.di.generic.instance
abstract class BaseWidgetServiceIntentClass : JobIntentService(){ abstract class BaseWidgetServiceIntentClass<T: AppWidgetProvider> : JobIntentService(){
private val kodein = LateInitKodein() lateinit var appWidgetManager: AppWidgetManager
val helper: ServicesHelper by kodein.instance() lateinit var appWidgetIds: IntArray
fun setKodein(context: Context){ fun initBaseWidget(componentName: ComponentName){
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein appWidgetManager = AppWidgetManager.getInstance(baseContext)
appWidgetIds = appWidgetManager.getAppWidgetIds(componentName)
} }
fun createRemoteView(context: Context, @LayoutRes id: Int): RemoteViews { fun createRemoteView(@LayoutRes id: Int): RemoteViews {
return RemoteViews(context.packageName, id) return RemoteViews(packageName, id)
} }
// Create pending intent commonly used for 'click to update' features // Create pending intent commonly used for 'click to update' features
fun <T: AppWidgetProvider> createUpdatePendingIntent( fun createUpdatePendingIntent(
appWidgetProvider: Class<T>, appWidgetProvider: Class<T>,
context: Context,
appWidgetId: Int appWidgetId: Int
): PendingIntent? { ): PendingIntent? {
val seconds = (System.currentTimeMillis() / 1000L).toInt() val seconds = (System.currentTimeMillis() / 1000L).toInt()
val intentUpdate = Intent(context.applicationContext, appWidgetProvider) val intentUpdate = Intent(applicationContext, appWidgetProvider)
intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
val idArray = intArrayOf(appWidgetId) val idArray = intArrayOf(appWidgetId)
intentUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, idArray) intentUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, idArray)
return PendingIntent.getBroadcast( return PendingIntent.getBroadcast(
context, seconds, intentUpdate, this, seconds, intentUpdate,
PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT)
} }
@@ -48,11 +54,26 @@ abstract class BaseWidgetServiceIntentClass : JobIntentService(){
* create a pending intent used to navigate to activity: * create a pending intent used to navigate to activity:
* @param activityClass * @param activityClass
*/ */
fun <T: Activity> createClickingPendingIntent(context: Context, activityClass: Class<T>): PendingIntent { fun <T: Activity> createClickingPendingIntent(activityClass: Class<T>): PendingIntent {
val clickIntentTemplate = Intent(context, activityClass) val clickIntentTemplate = Intent(this, activityClass)
return TaskStackBuilder.create(context) return TaskStackBuilder.create(this)
.addNextIntentWithParentStack(clickIntentTemplate) .addNextIntentWithParentStack(clickIntentTemplate)
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT) .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?) {}
} }

View File

@@ -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
}

View File

@@ -3,187 +3,178 @@ package com.appttude.h_mal.atlas_weather.monoWeather.widget
import android.Manifest.permission.ACCESS_COARSE_LOCATION import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.PendingIntent import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.net.Uri import android.icu.text.SimpleDateFormat
import android.os.PowerManager import android.os.PowerManager
import android.widget.RemoteViews import android.widget.RemoteViews
import android.os.Build
import androidx.core.app.ActivityCompat.checkSelfPermission import androidx.core.app.ActivityCompat.checkSelfPermission
import com.appttude.h_mal.atlas_weather.R 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.InnerWidgetCellData
import com.appttude.h_mal.atlas_weather.model.widget.WidgetWeatherCollection 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.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.isInternetAvailable
import com.appttude.h_mal.atlas_weather.utils.tryOrNullSuspended import com.appttude.h_mal.atlas_weather.utils.tryOrNullSuspended
import com.squareup.picasso.Picasso
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.LocalDateTime import org.kodein.di.KodeinAware
import java.time.format.DateTimeFormatter 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) { override fun onHandleWork(intent: Intent) {
// We have received work to do. The system or framework is already // 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. // holding a wake lock for us at this point, so we can just go.
kodein.baseKodein = (applicationContext as KodeinAware).kodein
executeWidgetUpdate() executeWidgetUpdate()
} }
private fun executeWidgetUpdate() { private fun executeWidgetUpdate() {
setKodein(this) val componentName = ComponentName(this, NewAppWidget::class.java)
initBaseWidget(componentName)
val appWidgetManager = AppWidgetManager.getInstance(this) initiateWidgetUpdate(getCurrentWidgetState())
val thisAppWidget = ComponentName(packageName, NewAppWidget::class.java.name) }
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
validateOperation()?.let { private fun initiateWidgetUpdate(state: WidgetState) {
if (it) updateWidget(appWidgetIds, appWidgetManager) when (state) {
else updateErrorWidget(appWidgetIds, appWidgetManager) 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 { CoroutineScope(Dispatchers.IO).launch {
val result = getWidgetWeather() val result = getWidgetWeather(fromStorage)
appWidgetIds.forEach { id -> setupView(id, result) }
for (appWidgetId in appWidgetIds) {
bindView(this@WidgetJobServiceIntent, appWidgetManager, appWidgetId, result)
}
}
}
private fun updateErrorWidget(appWidgetIds: IntArray, appWidgetManager: AppWidgetManager){
for (appWidgetId in appWidgetIds) {
setEmptyView(this, appWidgetManager, appWidgetId)
} }
} }
private fun validateOperation(): Boolean? { private fun updateErrorWidget(state: WidgetState) {
appWidgetIds.forEach { id -> setEmptyView(id, state) }
}
private fun getCurrentWidgetState(): WidgetState {
val pm = getSystemService(POWER_SERVICE) as PowerManager val pm = getSystemService(POWER_SERVICE) as PowerManager
val isScreenOn = pm.isInteractive val isScreenOn = pm.isInteractive
val locationGranted = val locationGranted =
checkSelfPermission(this, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED checkSelfPermission(this, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
val internetAvailable = isInternetAvailable(this.applicationContext) val internetAvailable = isInternetAvailable(this.applicationContext)
// no location return false return getWidgetState(locationGranted, isScreenOn, internetAvailable)
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))
}
} }
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
suspend fun getWidgetWeather(): WidgetWeatherCollection? { suspend fun getWidgetWeather(storageOnly: Boolean): WidgetWeatherCollection? {
return tryOrNullSuspended { return tryOrNullSuspended {
helper.fetchData() if (!storageOnly) helper.fetchData()
helper.getWidgetWeatherCollection() helper.getWidgetWeatherCollection()
} }
} }
private fun setEmptyView(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) { private fun setEmptyView(appWidgetId: Int, state: WidgetState) {
try { val error = when (state) {
val error = if (checkSelfPermission(context, ACCESS_COARSE_LOCATION) NO_LOCATION -> "No Location Permission"
!= PERMISSION_GRANTED) { SCREEN_ON_CONNECTION_UNAVAILABLE -> "No network available"
"No Permission" else -> "No data"
} 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 bindEmptyView( val views = createRemoteView(R.layout.weather_app_widget)
appWidgetManager: AppWidgetManager, bindErrorView(appWidgetId, views, error)
}
private fun setupView(
appWidgetId: Int, appWidgetId: Int,
views: RemoteViews, collection: WidgetWeatherCollection?
clickingUpdateIntent: PendingIntent?,
warning: String
) { ) {
setLastUpdated(views) val views = createRemoteView(R.layout.weather_app_widget)
views.setTextViewText(R.id.widget_current_location, warning) setLastUpdated(views, collection?.widgetData?.timeStamp)
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)
views.setInt(R.id.whole_widget_view, "setBackgroundColor", helper.getWidgetBackground()) views.setInt(R.id.whole_widget_view, "setBackgroundColor", helper.getWidgetBackground())
val clickingUpdatePendingIntent = createUpdatePendingIntent(NewAppWidget::class.java, context, appWidgetId)
if (collection != null) { if (collection != null) {
val clickPendingIntentTemplate = bindView(appWidgetId, views, collection)
createClickingPendingIntent(context, MainActivity::class.java) } else {
bindEmptyView(appWidgetId, views, "No weather available")
}
}
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 { views.apply {
val weather = collection.widgetData 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_main_temp, weather.currentTemp)
setTextViewText(R.id.widget_feel_temp, "°C") setTextViewText(R.id.widget_feel_temp, "°C")
setTextViewText(R.id.widget_current_location, weather.location) setTextViewText(R.id.widget_current_location, weather.location)
setImageViewResource(R.id.location_icon, R.drawable.location_flag) setImageViewResource(R.id.location_icon, R.drawable.location_flag)
CoroutineScope(Dispatchers.Main).launch { setImageView(weather.icon, this, R.id.widget_current_icon, widgetId)
Picasso.get().load(weather.icon).into(views, R.id.widget_current_icon, intArrayOf(appWidgetId)) setOnClickPendingIntent(R.id.widget_current_icon, clickUpdate)
} setOnClickPendingIntent(R.id.widget_current_location, clickUpdate)
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)
}
loadCells(widgetId, this, collection.forecast, clickToMain)
// Instruct the widget manager to update the widget // Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views) appWidgetManager.updateAppWidget(widgetId, views)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_listview) }
} else {
bindEmptyView(appWidgetManager, appWidgetId, views, clickingUpdatePendingIntent, "No Connection")
} }
} private fun loadCells(
appWidgetId: Int,
private fun loadCells(appWidgetId: Int, remoteViews: RemoteViews, weather: List<InnerWidgetCellData>){ remoteViews: RemoteViews,
weather: List<InnerWidgetCellData>,
clickIntent: PendingIntent
) {
(0..4).forEach { i -> (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 dayId: Int = resources.getIdentifier("widget_item_day_$i", "id", packageName)
val imageId: Int = resources.getIdentifier("widget_item_image_$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) 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(dayId, it.date)
remoteViews.setTextViewText(tempId, it.highTemp) remoteViews.setTextViewText(tempId, it.highTemp)
CoroutineScope(Dispatchers.Main).launch { setImageView(it.icon, remoteViews, imageId, appWidgetId)
Picasso.get().load(it.icon).into(remoteViews, imageId, intArrayOf(appWidgetId)) remoteViews.setOnClickPendingIntent(containerId, clickIntent)
}
} }
} }
private fun setLastUpdated(views: RemoteViews){ private fun setLastUpdated(views: RemoteViews, timeStamp: Long?) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && timeStamp != null) {
val current = LocalDateTime.now() val difference = System.currentTimeMillis().minus(timeStamp)
val formatter = DateTimeFormatter.ofPattern("HH:mm")
val formatted = current.format(formatter) val status = if (difference > HALF_DAY) {
views.setTextViewText(R.id.widget_current_status, "last updated: $formatted") "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")
} }
} }

View File

@@ -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)
}
}

View File

@@ -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
}
}
}

View File

@@ -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)
}