mirror of
https://github.com/hmalik144/Weather-apps.git
synced 2025-12-10 02:05:20 +00:00
- Commit latest to main
Took 14 minutes
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
/projectFilesBackup
|
||||
|
||||
2
app/.gitignore
vendored
2
app/.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
/build
|
||||
/release
|
||||
/atlasWeather
|
||||
/monoWeather
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -13,3 +13,15 @@ data class InnerWidgetData(
|
||||
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>
|
||||
)
|
||||
BIN
app/src/main/res/drawable/location_permission_decl.png
Normal file
BIN
app/src/main/res/drawable/location_permission_decl.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -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>
|
||||
@@ -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" />
|
||||
|
||||
|
||||
|
||||
15
app/src/main/res/values-v26/styles.xml
Normal file
15
app/src/main/res/values-v26/styles.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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,11 +48,9 @@
|
||||
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"
|
||||
@@ -55,5 +58,3 @@
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user