- Commit latest to main

Took 14 minutes
This commit is contained in:
2022-02-06 17:56:36 +00:00
parent e4c8c45e5c
commit d2bffab2e1
26 changed files with 498 additions and 112 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@
/build
/captures
.externalNativeBuild
/projectFilesBackup

2
app/.gitignore vendored
View File

@@ -1,2 +1,4 @@
/build
/release
/atlasWeather
/monoWeather

View File

@@ -15,7 +15,7 @@ import com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.android.synthetic.atlasWeather.activity_main.*
class MainActivity : BaseActivity() {
class MainActivity : BaseActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@@ -57,13 +57,13 @@ class HomeFragment : BaseFragment(), KodeinAware {
adapter = recyclerAdapter
}
getPermissionResult(Manifest.permission.ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST){
getPermissionResult(Manifest.permission.ACCESS_FINE_LOCATION, LOCATION_PERMISSION_REQUEST){
viewModel.fetchData()
}
swipe_refresh.apply {
setOnRefreshListener {
getPermissionResult(Manifest.permission.ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST){
getPermissionResult(Manifest.permission.ACCESS_FINE_LOCATION, LOCATION_PERMISSION_REQUEST){
viewModel.fetchData()
}
isRefreshing = true

View File

@@ -6,7 +6,6 @@
<item name="colorPrimary">@android:color/black</item>
<item name="colorPrimaryDark">@color/colour_four</item>
<item name="colorAccent">@color/colour_one</item>
<item name="android:windowBackground">@drawable/gradient</item>
<item name="fontFamily">sans-serif-light</item>
<item name="android:textColor">@color/colorAccent</item>
</style>
@@ -14,17 +13,14 @@
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowBackground">@drawable/gradient</item>
</style>
<style name="TextAppearance.AppCompat.Widget.ActionBar.Title" parent="@android:style/TextAppearance">
<item name="android:fontFamily">@font/archeologicaps</item>
<!--<item name="android:textColor">@color/colour_five</item>-->
</style>
<style name="titlebar" parent="@android:style/TextAppearance">
<item name="android:fontFamily">@font/archeologicaps</item>
<!--<item name="android:textColor">@color/colour_five</item>-->
</style>

View File

@@ -68,7 +68,7 @@ class LocationProviderImpl(
@SuppressLint("MissingPermission")
private suspend fun getAFreshLocation(): Location? {
return client.getCurrentLocation(PRIORITY_HIGH_ACCURACY, object : CancellationToken() {
return client.getCurrentLocation(PRIORITY_LOW_POWER, object : CancellationToken() {
override fun isCancellationRequested(): Boolean = false
override fun onCanceledRequested(p0: OnTokenCanceledListener): CancellationToken = this
}).await()

View File

@@ -11,8 +11,10 @@ import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepository
import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetCellData
import com.appttude.h_mal.atlas_weather.model.widget.InnerWidgetData
import com.appttude.h_mal.atlas_weather.model.widget.WidgetData
import com.appttude.h_mal.atlas_weather.model.widget.WidgetWeatherCollection
import com.appttude.h_mal.atlas_weather.utils.toSmallDayName
import com.squareup.picasso.Picasso
import com.squareup.picasso.Target
@@ -92,6 +94,36 @@ class ServicesHelper(
}
}
suspend fun getWidgetWeatherCollection(): WidgetWeatherCollection? {
return try {
val result = repository.loadSingleCurrentWeatherFromRoom(CURRENT_LOCATION)
val widgetData = 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)
}
val list = mutableListOf<InnerWidgetCellData>()
result.weather.daily?.drop(1)?.dropLast(2)?.forEach { dailyWeather ->
val day = dailyWeather.dt?.toSmallDayName()
val icon = dailyWeather.icon
val temp = dailyWeather.max?.toInt().toString()
val item = InnerWidgetCellData(day, icon, temp)
list.add(item)
}
list.toList()
WidgetWeatherCollection(widgetData, list)
} catch (e: Exception) {
null
}
}
private suspend fun getBitmapFromUrl(imageAddress: String?): Bitmap? {
return suspendCoroutine { cont ->
Picasso.get().load(imageAddress).into(object : Target {

View File

@@ -12,4 +12,16 @@ data class InnerWidgetData(
val date: String?,
val icon: Bitmap?,
val highTemp: String?
)
data class InnerWidgetCellData(
val date: String?,
val icon: String?,
val highTemp: String?
)
data class WidgetWeatherCollection(
val widgetData: WidgetData,
val forecast: List<InnerWidgetCellData>
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,25 +1,27 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/whole_widget_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:background="@android:color/black"
tools:layout_height="110dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/central"
android:layout_height="0dp"
android:layout_alignParentTop="true"
android:layout_weight="1"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_marginStart="12dp">
android:layout_marginStart="12dp"
android:orientation="vertical">
<TextClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -34,8 +36,8 @@
android:id="@+id/widget_current_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="180dp"
android:includeFontPadding="false"
android:maxWidth="180dp"
android:maxLines="1"
android:textColor="#ffffff"
android:textSize="12sp"
@@ -46,11 +48,11 @@
android:id="@+id/widget_current_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/location_container"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:layout_above="@id/location_container"
android:adjustViewBounds="true"
android:layout_marginLeft="32dp"
android:adjustViewBounds="true"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<LinearLayout
@@ -59,7 +61,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
android:layout_marginBottom="6dp"
android:layout_marginBottom="1dp"
android:orientation="horizontal">
<ImageView
@@ -77,16 +79,9 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:maxWidth="180dp"
android:autoSizeMaxTextSize="100sp"
android:autoSizeMinTextSize="12sp"
android:autoSizeStepGranularity="2sp"
android:autoSizeTextType="uniform"
android:gravity=""
android:includeFontPadding="false"
android:maxLines="1"
android:textColor="#ffffff"
android:textSize="12sp"
tools:text="Roehampton" />
style="@style/widget_light_home_text"
tools:text="Hammersmith Bridge" />
</LinearLayout>
@@ -128,23 +123,172 @@
</RelativeLayout>
<LinearLayout
android:id="@+id/central"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_centerInParent="true"
android:orientation="vertical" />
<GridView
<GridLayout
android:id="@+id/widget_listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/central"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
android:adjustViewBounds="true"
android:numColumns="5"
tools:listitem="@layout/widget_item"/>
android:layout_weight="1"
android:columnCount="5"
android:rowCount="1">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:orientation="vertical">
<TextView
android:id="@+id/widget_item_day_0"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Wed" />
<ImageView
android:id="@+id/widget_item_image_0"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
android:id="@+id/widget_item_temp_high_0"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="20" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:orientation="vertical">
<TextView
android:id="@+id/widget_item_day_1"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Wed" />
<ImageView
android:id="@+id/widget_item_image_1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
android:id="@+id/widget_item_temp_high_1"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="20" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:orientation="vertical">
<TextView
android:id="@+id/widget_item_day_2"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Wed" />
<ImageView
android:id="@+id/widget_item_image_2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
android:id="@+id/widget_item_temp_high_2"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="20" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:orientation="vertical">
<TextView
android:id="@+id/widget_item_day_3"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Wed" />
<ImageView
android:id="@+id/widget_item_image_3"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
android:id="@+id/widget_item_temp_high_3"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="20" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_columnWeight="1"
android:orientation="vertical">
<TextView
android:id="@+id/widget_item_day_4"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Wed" />
<ImageView
android:id="@+id/widget_item_image_4"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:adjustViewBounds="true"
tools:src="@drawable/ic_baseline_cloud_off_24" />
<TextView
android:id="@+id/widget_item_temp_high_4"
style="@style/widget_light_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="20" />
</LinearLayout>
</GridLayout>
</LinearLayout>

View File

@@ -3,9 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/widget_item_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:minHeight="55dp">
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/widget_item_day"
@@ -15,14 +14,19 @@
android:gravity="center"
android:includeFontPadding="false"
android:textColor="#ffffff"
android:textSize="12sp"
android:autoSizeMaxTextSize="100sp"
android:autoSizeMinTextSize="8sp"
android:autoSizeStepGranularity="2sp"
android:autoSizeTextType="uniform"
tools:text="Wed" />
<ImageView
android:id="@+id/widget_item_image"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:layout_gravity="center"
android:adjustViewBounds="true"
tools:src="@drawable/ic_baseline_cloud_off_24" />
@@ -35,6 +39,10 @@
android:gravity="center"
android:textColor="#ffffff"
android:textSize="12sp"
android:autoSizeMaxTextSize="100sp"
android:autoSizeMinTextSize="8sp"
android:autoSizeStepGranularity="2sp"
android:autoSizeTextType="uniform"
tools:text="20" />

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="widget_light_text">
<item name="android:layout_gravity">center</item>
<item name="android:autoSizeMaxTextSize">100sp</item>
<item name="android:autoSizeMinTextSize">8sp</item>
<item name="android:autoSizeStepGranularity">2sp</item>
<item name="android:autoSizeTextType">uniform</item>
<item name="android:gravity">center</item>
<item name="android:includeFontPadding">false</item>
<item name="android:textColor">#ffffff</item>
<item name="android:textSize">12sp</item>
</style>
</resources>

View File

@@ -5,5 +5,6 @@
Refer to App Widget Documentation for margin information
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View File

@@ -8,4 +8,23 @@
<item name="android:layout_marginBottom">12dp</item>
<item name="android:layout_weight">2</item>
</style>
<style name="widget_light_text" parent="widget_light_base">
<item name="android:autoSizeMinTextSize">8sp</item>
</style>
<style name="widget_light_home_text" parent="widget_light_base">
<item name="android:autoSizeMinTextSize">12sp</item>
</style>
<style name="widget_light_base">
<item name="android:layout_gravity">center</item>
<item name="android:autoSizeMaxTextSize">100sp</item>
<item name="android:autoSizeStepGranularity">2sp</item>
<item name="android:autoSizeTextType">uniform</item>
<item name="android:gravity">center</item>
<item name="android:includeFontPadding">false</item>
<item name="android:textColor">#ffffff</item>
<item name="android:textSize">12sp</item>
</style>
</resources>

View File

@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:configure="com.appttude.h_mal.atlas_weather.monoWeather.ui.widget.WidgetLocationPermissionActivity"
android:initialKeyguardLayout="@layout/weather_app_widget"
android:initialLayout="@layout/weather_app_widget"
android:minHeight="110.0dp"
android:minWidth="350.0dp"
android:minResizeWidth="350.0dp"
android:minWidth="320.0dp"
android:minResizeWidth="320.0dp"
android:minResizeHeight="110.0dp"
android:previewImage="@drawable/widget_screenshot"
android:updatePeriodMillis="1800000"

View File

@@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<application
@@ -14,8 +14,8 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:node="merge">
<activity android:name="com.appttude.h_mal.atlas_weather.monoWeather.ui.MainActivity"
<activity
android:name="com.appttude.h_mal.atlas_weather.monoWeather.ui.MainActivity"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/AppTheme.NoActionBar">
@@ -26,11 +26,16 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.appttude.h_mal.atlas_weather.monoWeather.ui.settings.UnitSettingsActivity"
android:label="Settings" />
<activity android:name="com.appttude.h_mal.atlas_weather.monoWeather.ui.widget.WidgetLocationPermissionActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<receiver android:name="com.appttude.h_mal.atlas_weather.monoWeather.widget.NewAppWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@@ -43,17 +48,13 @@
android:resource="@xml/new_app_widget_info" />
</receiver>
<service
android:name="com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetRemoteViewsService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<service
android:name="com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetJobServiceIntent"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
</application>
</manifest>
</manifest>

View File

@@ -24,7 +24,7 @@ import org.kodein.di.android.x.kodein
import org.kodein.di.generic.instance
import kotlin.properties.Delegates
abstract class BaseFragment : Fragment(), KodeinAware {
abstract class BaseFragment() : Fragment(), KodeinAware {
override val kodein by kodein()
val factory by instance<ApplicationViewModelFactory>()

View File

@@ -7,11 +7,9 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
import com.appttude.h_mal.atlas_weather.monoWeather.ui.details.FurtherInfoFragmentArgs
import kotlinx.android.synthetic.main.activity_further_info.*
private const val WEATHER = "param1"
/**
* A simple [Fragment] subclass.
* Use the [FurtherInfoFragment.newInstance] factory method to

View File

@@ -24,7 +24,7 @@ import kotlinx.android.synthetic.main.fragment_home.*
* A simple [Fragment] subclass.
* create an instance of this fragment.
*/
class HomeFragment : BaseFragment(){
class HomeFragment : BaseFragment() {
private val viewModel by getFragmentViewModel<MainViewModel>()
@@ -49,6 +49,7 @@ class HomeFragment : BaseFragment(){
adapter = recyclerAdapter
}
getPermissionResult(Manifest.permission.ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST){
viewModel.fetchData()
}

View File

@@ -0,0 +1,86 @@
package com.appttude.h_mal.atlas_weather.monoWeather.ui.widget
import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.app.Activity
import android.appwidget.AppWidgetManager.*
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat.checkSelfPermission
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.utils.displayToast
import kotlinx.android.synthetic.monoWeather.permissions_declaration_dialog.*
const val PERMISSION_CODE = 401
class WidgetLocationPermissionActivity : AppCompatActivity() {
private var mAppWidgetId = INVALID_APPWIDGET_ID
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set the result to CANCELED. This will cause the widget host to cancel
// out of the widget placement if the user presses the back button.
setResult(RESULT_CANCELED)
// Find the widget id from the intent.
intent.extras?.let {
mAppWidgetId = it.getInt(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID)
}
// If this activity was started with an intent without an app widget ID, finish with an error.
if (mAppWidgetId == INVALID_APPWIDGET_ID) {
finish()
return
}
setContentView(R.layout.permissions_declaration_dialog)
submit.setOnClickListener {
if (checkSelfPermission(this, ACCESS_COARSE_LOCATION) != PERMISSION_GRANTED) {
requestPermissions(arrayOf(ACCESS_COARSE_LOCATION), PERMISSION_CODE)
} else {
submitWidget()
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_CODE) {
if (grantResults.isNotEmpty() && grantResults[0] == PERMISSION_GRANTED) {
submitWidget()
} else {
displayToast("Location Permission denied")
}
}
}
private fun submitWidget() {
sendUpdateIntent()
finishCurrencyWidgetActivity()
}
private fun finishCurrencyWidgetActivity() {
// Make sure we pass back the original appWidgetId
val resultValue = intent
resultValue.putExtra(EXTRA_APPWIDGET_ID, mAppWidgetId)
setResult(Activity.RESULT_OK, resultValue)
finish()
}
private fun sendUpdateIntent() {
// It is the responsibility of the configuration activity to update the app widget
// Send update broadcast to widget app class
Intent(this@WidgetLocationPermissionActivity,
WidgetLocationPermissionActivity::class.java
).apply {
action = ACTION_APPWIDGET_UPDATE
// Put current app widget ID into extras and send broadcast
putExtra(EXTRA_APPWIDGET_IDS, intArrayOf(mAppWidgetId))
sendBroadcast(this)
}
}
}

View File

@@ -9,7 +9,6 @@ import androidx.lifecycle.observe
import androidx.recyclerview.widget.LinearLayoutManager
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.monoWeather.ui.BaseFragment
import com.appttude.h_mal.atlas_weather.monoWeather.ui.WorldItemFragmentDirections
import com.appttude.h_mal.atlas_weather.monoWeather.ui.world.WorldFragmentDirections.actionWorldFragmentToWorldItemFragment
import com.appttude.h_mal.atlas_weather.utils.navigateTo
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel

View File

@@ -35,7 +35,6 @@ class MyWidgetRemoteViewsFactory(
override fun getViewAt(i: Int): RemoteViews {
val rv = RemoteViews(context.packageName, R.layout.widget_item)
if (list.isNullOrEmpty()) return rv
list?.get(i)?.let {
@@ -57,4 +56,5 @@ class MyWidgetRemoteViewsFactory(
override fun getItemId(i: Int): Long = i.toLong()
override fun hasStableIds(): Boolean = true
}

View File

@@ -4,6 +4,7 @@ import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.appttude.h_mal.atlas_weather.monoWeather.widget.WidgetJobServiceIntent.Companion.enqueueWork
/**

View File

@@ -1,19 +1,20 @@
package com.appttude.h_mal.atlas_weather.monoWeather.widget
import android.Manifest
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
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.net.Uri
import android.os.PowerManager
import android.widget.RemoteViews
import androidx.core.app.ActivityCompat
import androidx.core.app.ActivityCompat.checkSelfPermission
import com.appttude.h_mal.atlas_weather.R
import com.appttude.h_mal.atlas_weather.model.widget.WidgetData
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.utils.isInternetAvailable
import com.appttude.h_mal.atlas_weather.utils.tryOrNullSuspended
@@ -34,11 +35,7 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass() {
// 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.
val pm = getSystemService(POWER_SERVICE) as PowerManager
val isScreenOn = pm.isInteractive
// If screen is on then update widget or do nothing
if (isScreenOn) executeWidgetUpdate()
executeWidgetUpdate()
}
private fun executeWidgetUpdate(){
@@ -48,23 +45,45 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass() {
val thisAppWidget = ComponentName(packageName, NewAppWidget::class.java.name)
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
// Check if we have an active connection and permissions granted
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED || !isInternetAvailable(this.applicationContext)) {
for (appWidgetId in appWidgetIds) {
setEmptyView(this, appWidgetManager, appWidgetId)
}
}else{
CoroutineScope(Dispatchers.IO).launch {
val result = getWidgetWeather()
validateOperation()?.let {
if (it) updateWidget(appWidgetIds, appWidgetManager)
else updateErrorWidget(appWidgetIds, appWidgetManager)
}
}
for (appWidgetId in appWidgetIds) {
bindView(this@WidgetJobServiceIntent, appWidgetManager, appWidgetId, result)
}
private fun updateWidget(appWidgetIds: IntArray, appWidgetManager: AppWidgetManager){
CoroutineScope(Dispatchers.IO).launch {
val result = getWidgetWeather()
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? {
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
@@ -76,18 +95,17 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass() {
}
@SuppressLint("MissingPermission")
suspend fun getWidgetWeather(): WidgetData? {
suspend fun getWidgetWeather(): WidgetWeatherCollection? {
return tryOrNullSuspended {
helper.fetchData()
helper.getWidgetWeather()
helper.getWidgetWeatherCollection()
}
}
private fun setEmptyView(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
try {
val error = if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
val error = if (checkSelfPermission(context, ACCESS_COARSE_LOCATION)
!= PERMISSION_GRANTED) {
"No Permission"
} else if (!isInternetAvailable(context.applicationContext)) {
"No Connection"
@@ -100,7 +118,6 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass() {
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun bindEmptyView(
@@ -128,18 +145,19 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass() {
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int,
weather: WidgetData?) {
collection: WidgetWeatherCollection?) {
val views = createRemoteView(context, R.layout.weather_app_widget)
setLastUpdated(views)
views.setInt(R.id.whole_widget_view, "setBackgroundColor", helper.getWidgetBackground())
val clickingUpdatePendingIntent = createUpdatePendingIntent(NewAppWidget::class.java, context, appWidgetId)
val forecastListIntent = createForecastListIntent(context, appWidgetId)
if (weather != null) {
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)
@@ -151,7 +169,8 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass() {
setOnClickPendingIntent(R.id.widget_current_icon, clickingUpdatePendingIntent)
setOnClickPendingIntent(R.id.widget_current_location, clickingUpdatePendingIntent)
setRemoteAdapter(R.id.widget_listview, forecastListIntent)
loadCells(appWidgetId, views, collection.forecast)
// setRemoteAdapter(R.id.widget_listview, forecastListIntent)
}
// Instruct the widget manager to update the widget
@@ -163,6 +182,22 @@ class WidgetJobServiceIntent : BaseWidgetServiceIntentClass() {
}
private fun loadCells(appWidgetId: Int, remoteViews: RemoteViews, weather: List<InnerWidgetCellData>){
(0..4).forEach { i ->
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)
val it = weather[i]
remoteViews.setTextViewText(dayId, it.date)
remoteViews.setTextViewText(tempId, it.highTemp)
CoroutineScope(Dispatchers.Main).launch {
Picasso.get().load(it.icon).into(remoteViews, imageId, intArrayOf(appWidgetId))
}
}
}
private fun setLastUpdated(views: RemoteViews){
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
val current = LocalDateTime.now()

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="128dp"
android:tint="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"
app:srcCompat="@drawable/location_permission_decl" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/imageView"
android:layout_marginLeft="64dp"
android:layout_marginRight="64dp"
app:layout_constraintVertical_bias="0.2"
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos."/>
<Button
android:id="@+id/submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.85"
app:layout_constraintHorizontal_bias="0.9"
android:backgroundTint="@android:color/white"
android:textColor="@android:color/black"
android:text="Ok" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,17 +0,0 @@
package com.appttude.h_mal.atlas_weather;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}