First Commit

This commit is contained in:
Tommaso Berlose 2017-10-06 18:13:30 +02:00
commit 13ba1e3281
116 changed files with 1973 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild

18
.idea/gradle.xml generated Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

89
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State>
<id />
</State>
<State>
<id>Android &gt; Lint &gt; Correctness</id>
</State>
<State>
<id>Android &gt; Lint &gt; Performance</id>
</State>
<State>
<id>Class structureJava</id>
</State>
<State>
<id>Cloning issuesJava</id>
</State>
<State>
<id>Groovy</id>
</State>
<State>
<id>Inheritance issuesJava</id>
</State>
<State>
<id>Internationalization issuesJava</id>
</State>
<State>
<id>Java</id>
</State>
<State>
<id>Numeric issuesJava</id>
</State>
<State>
<id>Performance issuesJava</id>
</State>
<State>
<id>Potentially confusing code constructsGroovy</id>
</State>
<State>
<id>Probable bugsJava</id>
</State>
<State>
<id>Security issuesJava</id>
</State>
<State>
<id>Serialization issuesJava</id>
</State>
<State>
<id>Threading issuesJava</id>
</State>
</expanded-state>
</profile-state>
</entry>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

9
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/another-widget.iml" filepath="$PROJECT_DIR$/another-widget.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
</project>

12
.idea/runConfigurations.xml generated Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

41
app/build.gradle Normal file
View File

@ -0,0 +1,41 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 26
buildToolsVersion "26.0.2"
defaultConfig {
applicationId "com.tommasoberlose.anotherwidget"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
compile 'com.survivingwithandroid:weatherlib:1.6.0'
compile 'com.survivingwithandroid:weatherlib_volleyclient:1.6.0'
compile 'com.mcxiaoke.volley:library:1.0.6@aar'
compile 'com.android.support:customtabs:26.1.0'
}

21
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,24 @@
package com.tommasoberlose.anotherwidget
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
assertEquals("com.tommasoberlose.anotherwidget", appContext.packageName)
}
}

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tommasoberlose.anotherwidget">
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".ui.activity.MainActivity"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".ui.widget.TheWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/the_widget_info" />
</receiver>
<receiver
android:name=".util.NewCalendarEventReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.PROVIDER_CHANGED" />
<data android:scheme="content" />
<data android:host="com.android.calendar" />
</intent-filter>
</receiver>
<receiver
android:name=".util.UpdatesReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name=".util.WeatherReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -0,0 +1,22 @@
package com.tommasoberlose.anotherwidget.`object`
import java.text.SimpleDateFormat
import java.util.*
/**
* Created by tommaso on 05/10/17.
*/
object Constants {
val CALENDAR_REQUEST_CODE = 1
val LOCATION_REQUEST_CODE = 2
val PREF_WEATHER_ICON = "PREF_WEATHER_ICON"
val PREF_WEATHER_TEMP = "PREF_WEATHER_TEMP"
val dateFormat = SimpleDateFormat("EEEE, MMM d", Locale.getDefault())
val hourFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val ACTION_TIME_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_TIME_UPDATE"
val ACTION_WEATHER_UPDATE = "com.tommasoberlose.anotherwidget.action.ACTION_WEATHER_UPDATE"
}

View File

@ -0,0 +1,28 @@
package com.tommasoberlose.anotherwidget.`object`
import android.database.Cursor
import java.util.Date
/**
* Created by tommaso on 05/10/17.
*/
class Event(eventCursor: Cursor, instanceCursor: Cursor) {
var id: Int = 0
var title: String? = null
var startDate: Long = 0
var endDate: Long = 0
init {
id = instanceCursor.getInt(0)
startDate = instanceCursor.getLong(1)
endDate = instanceCursor.getLong(2)
title = eventCursor.getString(0)
}
override fun toString(): String {
return "Event:\nID" + id + "\nTITLE: " + title + "\nSTART DATE: " + Date(startDate) + "\nEND DATE: " + Date(endDate)
}
}

View File

@ -0,0 +1,95 @@
package com.tommasoberlose.anotherwidget.ui.activity
import android.Manifest
import android.content.pm.PackageManager
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.appwidget.AppWidgetManager
import android.content.Intent
import android.content.ComponentName
import android.view.View
import android.widget.Toast
import com.tommasoberlose.anotherwidget.`object`.Constants
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.util.Util
import com.tommasoberlose.anotherwidget.ui.widget.TheWidget
import com.tommasoberlose.anotherwidget.util.UpdatesReceiver
import com.tommasoberlose.anotherwidget.util.WeatherReceiver
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
action_support.setOnClickListener(object: View.OnClickListener {
override fun onClick(p0: View?) {
Util.openURI(this@MainActivity, "https://paypal.me/tommasoberlose")
}
})
action_rate.setOnClickListener(object: View.OnClickListener {
override fun onClick(p0: View?) {
Util.openURI(this@MainActivity, "")
}
})
action_share.setOnClickListener(object: View.OnClickListener {
override fun onClick(p0: View?) {
Util.share(this@MainActivity)
}
})
}
override fun onResume() {
super.onResume()
updateUI()
Util.updateWidget(this)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
grantResults: IntArray) {
when (requestCode) {
Constants.CALENDAR_REQUEST_CODE -> if (permissions.size != 1 || grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
UpdatesReceiver().removeUpdates(this)
} else {
UpdatesReceiver().setUpdates(this)
}
Constants.LOCATION_REQUEST_CODE -> if (permissions.size != 1 || grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
WeatherReceiver().removeUpdates(this)
} else {
WeatherReceiver().setUpdates(this)
}
}
}
fun updateUI() {
no_calendar_permission_container.visibility= View.GONE
no_location_permission_container.visibility= View.GONE
if (!Util.checkGrantedPermission(this, Manifest.permission.READ_CALENDAR)) {
no_calendar_permission_container.visibility = View.VISIBLE
request_calendar.setOnClickListener(object: View.OnClickListener {
override fun onClick(view: View?) {
ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.READ_CALENDAR), Constants.CALENDAR_REQUEST_CODE)
}
})
} else {
if (!Util.checkGrantedPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
no_location_permission_container.visibility = View.VISIBLE
request_location.setOnClickListener(object: View.OnClickListener {
override fun onClick(view: View?) {
ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), Constants.LOCATION_REQUEST_CODE)
}
})
}
}
}
}

View File

@ -0,0 +1,224 @@
package com.tommasoberlose.anotherwidget.ui.widget
import android.Manifest
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.preference.PreferenceManager
import android.util.Log
import android.view.View
import android.widget.RemoteViews
import com.tommasoberlose.anotherwidget.`object`.Constants
import com.tommasoberlose.anotherwidget.`object`.Event
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.ui.activity.MainActivity
import com.tommasoberlose.anotherwidget.util.UpdatesReceiver
import com.tommasoberlose.anotherwidget.util.Util
import com.tommasoberlose.anotherwidget.util.WeatherReceiver
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
import android.app.PendingIntent
import android.net.Uri
import android.provider.CalendarContract
import android.content.ContentUris
/**
* Implementation of App Widget functionality.
*/
class TheWidget : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onEnabled(context: Context) {
UpdatesReceiver().setUpdates(context)
WeatherReceiver().setUpdates(context)
Util.showNotification(context)
}
override fun onDisabled(context: Context) {
UpdatesReceiver().removeUpdates(context)
WeatherReceiver().removeUpdates(context)
}
companion object {
internal fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager,
appWidgetId: Int) {
var views = RemoteViews(context.packageName, R.layout.the_widget)
views = updateCalendarView(context, views, appWidgetId)
views = updateLocationView(context, views)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
fun updateCalendarView(context: Context, views: RemoteViews, widgetID: Int): RemoteViews {
val now = Calendar.getInstance()
val calendarLayout = Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)
views.setViewVisibility(R.id.empty_layout, View.VISIBLE)
views.setViewVisibility(R.id.calendar_layout, View.GONE)
views.setTextViewText(R.id.empty_date, Constants.dateFormat.format(now.time))
val calIntent = Intent(Intent.ACTION_MAIN)
calIntent.addCategory(Intent.CATEGORY_APP_CALENDAR)
val calPIntent = PendingIntent.getActivity(context, widgetID, calIntent, 0)
views.setOnClickPendingIntent(R.id.main_layout, calPIntent)
if (calendarLayout) {
val eventList = Util.getNextEvent(context)
if (eventList.isNotEmpty()) {
val difference = eventList[0].startDate - now.timeInMillis
if (difference > 1000 * 60) {
var time = ""
val hour = TimeUnit.MILLISECONDS.toHours(difference)
if (hour > 0) {
time = hour.toString() + "h"
}
val minutes = TimeUnit.MILLISECONDS.toMinutes(difference - hour * 3600 * 1000)
if (minutes > 0) {
time += " " + minutes + "min"
}
views.setTextViewText(R.id.next_event, String.format("%s in %s", eventList[0].title, time))
} else {
views.setTextViewText(R.id.next_event, String.format("%s", eventList[0].title))
}
views.setTextViewText(R.id.next_event_date, String.format("%s - %s", Constants.hourFormat.format(eventList[0].startDate), Constants.hourFormat.format(eventList[0].endDate)))
views.setViewVisibility(R.id.empty_layout, View.GONE)
views.setViewVisibility(R.id.calendar_layout, View.VISIBLE)
val builder = CalendarContract.CONTENT_URI.buildUpon()
builder.appendPath("time")
ContentUris.appendId(builder, eventList[0].startDate)
val intent = Intent(Intent.ACTION_VIEW)
.setData(builder.build())
val pIntent = PendingIntent.getActivity(context, widgetID, intent, 0)
views.setOnClickPendingIntent(R.id.main_layout, pIntent)
}
}
return views
}
fun updateLocationView(context: Context, views: RemoteViews): RemoteViews {
val locationLayout = Util.checkGrantedPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
val SP = PreferenceManager.getDefaultSharedPreferences(context)
if (locationLayout && SP.contains(Constants.PREF_WEATHER_TEMP) && SP.contains(Constants.PREF_WEATHER_ICON)) {
views.setViewVisibility(R.id.weather, View.VISIBLE)
views.setViewVisibility(R.id.calendar_weather, View.VISIBLE)
val temp = String.format(Locale.getDefault(), "%.0f °C", SP.getFloat(Constants.PREF_WEATHER_TEMP, 0f))
views.setViewVisibility(R.id.weather_icon, View.VISIBLE)
views.setViewVisibility(R.id.empty_weather_icon, View.VISIBLE)
when (SP.getString(Constants.PREF_WEATHER_ICON, "")) {
"01d" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.clear_day)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.clear_day)
}
"02d" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.partly_cloudy)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.partly_cloudy)
}
"03d" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.mostly_cloudy)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.mostly_cloudy)
}
"04d" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.cloudy_weather)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.cloudy_weather)
}
"09d" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.storm_weather_day)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.storm_weather_day)
}
"10d" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.rainy_day)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.rainy_day)
}
"11d" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.thunder_day)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.thunder_day)
}
"13d" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.snow_day)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.snow_day)
}
"50d" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.haze_day)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.haze_day)
}
"01n" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.clear_night)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.clear_night)
}
"02n" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.partly_cloudy_night)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.partly_cloudy_night)
}
"03n" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.mostly_cloudy_night)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.mostly_cloudy_night)
}
"04n" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.cloudy_weather)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.cloudy_weather)
}
"09n" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.storm_weather_night)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.storm_weather_night)
}
"10n" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.rainy_night)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.rainy_night)
}
"11n" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.thunder_night)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.thunder_night)
}
"13n" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.snow_night)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.snow_night)
}
"50n" -> {
views.setImageViewResource(R.id.weather_icon, R.drawable.haze_night)
views.setImageViewResource(R.id.empty_weather_icon, R.drawable.haze_night)
}
else -> {
views.setViewVisibility(R.id.weather_icon, View.GONE)
views.setViewVisibility(R.id.empty_weather_icon, View.GONE)
}
}
views.setTextViewText(R.id.temp, temp)
views.setTextViewText(R.id.calendar_temp, temp)
} else {
views.setViewVisibility(R.id.weather, View.GONE)
views.setViewVisibility(R.id.calendar_weather, View.GONE)
}
return views
}
}
}

View File

@ -0,0 +1,12 @@
package com.tommasoberlose.anotherwidget.util
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
class NewCalendarEventReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Util.updateWidget(context)
}
}

View File

@ -0,0 +1,42 @@
package com.tommasoberlose.anotherwidget.util
import android.Manifest
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.R.string.cancel
import android.app.AlarmManager
import android.app.PendingIntent
import android.util.Log
import com.tommasoberlose.anotherwidget.`object`.Constants
class UpdatesReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action.equals(Intent.ACTION_BOOT_COMPLETED) || intent.action.equals(Intent.ACTION_INSTALL_PACKAGE) || intent.action.equals(Constants.ACTION_TIME_UPDATE)) {
Util.updateWidget(context)
}
}
fun setUpdates(context: Context) {
removeUpdates(context)
if (Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)) {
Util.updateWidget(context)
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val i = Intent(context, UpdatesReceiver::class.java)
i.action = Constants.ACTION_TIME_UPDATE
val pi = PendingIntent.getBroadcast(context, 0, i, 0)
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), (1000 * 60).toLong(), pi)
}
}
fun removeUpdates(context: Context) {
val intent = Intent(context, UpdatesReceiver::class.java)
val sender = PendingIntent.getBroadcast(context, 0, intent, 0)
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.cancel(sender)
}
}

View File

@ -0,0 +1,238 @@
package com.tommasoberlose.anotherwidget.util
import android.Manifest
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.*
import android.content.pm.PackageManager
import android.database.Cursor
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.net.Uri
import android.os.Bundle
import android.preference.PreferenceManager
import android.provider.CalendarContract
import android.support.customtabs.CustomTabsIntent
import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat
import android.util.Log
import com.survivingwithandroid.weather.lib.WeatherClient
import com.survivingwithandroid.weather.lib.WeatherConfig
import com.survivingwithandroid.weather.lib.exception.LocationProviderNotFoundException
import com.survivingwithandroid.weather.lib.exception.WeatherLibException
import com.survivingwithandroid.weather.lib.model.City
import com.survivingwithandroid.weather.lib.model.CurrentWeather
import com.survivingwithandroid.weather.lib.provider.forecastio.ForecastIOProviderType
import com.survivingwithandroid.weather.lib.provider.forecastio.ForecastIOWeatherProvider
import com.survivingwithandroid.weather.lib.provider.openweathermap.OpenweathermapProviderType
import com.survivingwithandroid.weather.lib.provider.yahooweather.YahooProviderType
import com.survivingwithandroid.weather.lib.request.WeatherRequest
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.`object`.Constants
import com.tommasoberlose.anotherwidget.`object`.Event
import com.tommasoberlose.anotherwidget.ui.activity.MainActivity
import com.tommasoberlose.anotherwidget.ui.widget.TheWidget
import java.util.ArrayList
import java.util.Calendar
/**
* Created by tommaso on 05/10/17.
*/
object Util {
fun checkGrantedPermission(context: Context, permission: String): Boolean {
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
}
fun getNextEvent(context: Context): List<Event> {
val eventList = ArrayList<Event>()
val now = Calendar.getInstance()
val hourLimit = Calendar.getInstance()
hourLimit.add(Calendar.HOUR, 6)
val builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
ContentUris.appendId(builder, now.timeInMillis)
ContentUris.appendId(builder, hourLimit.timeInMillis)
if (!checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)) {
return eventList
}
val instanceCursor = context.contentResolver.query(builder.build(), arrayOf(CalendarContract.Instances.EVENT_ID, CalendarContract.Instances.BEGIN, CalendarContract.Instances.END), null, null, null) ?: return eventList
instanceCursor.moveToFirst()
for (i in 0 until instanceCursor.count) {
val ID = instanceCursor.getInt(0)
val eventCursor = context.contentResolver.query(CalendarContract.Events.CONTENT_URI, arrayOf(CalendarContract.Events.TITLE),
CalendarContract.Events._ID + " is ?",
arrayOf(Integer.toString(ID)), null) ?: return eventList
eventCursor.moveToFirst()
for (j in 0 until eventCursor.count) {
val e = Event(eventCursor, instanceCursor)
if (e.endDate - now.timeInMillis > 1000 * 60 * 60) {
eventList.add(e)
}
eventCursor.moveToNext()
}
eventCursor.close()
instanceCursor.moveToNext()
}
instanceCursor.close()
return eventList
}
fun updateWidget(context: Context) {
val widgetManager = AppWidgetManager.getInstance(context)
val widgetComponent = ComponentName(context, TheWidget::class.java)
val widgetIds = widgetManager.getAppWidgetIds(widgetComponent)
val update = Intent()
update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds)
update.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
context.sendBroadcast(update)
}
fun getWeather(context: Context) {
if (!checkGrantedPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)) {
return
}
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
getCurrentWeather(context, locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER))
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0f, object: LocationListener {
override fun onLocationChanged(location: Location) {
locationManager.removeUpdates(this)
getCurrentWeather(context, location)
}
@SuppressLint("ApplySharedPref")
override fun onProviderDisabled(p0: String?) {
SP.edit()
.remove(Constants.PREF_WEATHER_TEMP)
.remove(Constants.PREF_WEATHER_ICON)
.commit()
}
@SuppressLint("ApplySharedPref")
override fun onProviderEnabled(p0: String?) {
SP.edit()
.remove(Constants.PREF_WEATHER_TEMP)
.remove(Constants.PREF_WEATHER_ICON)
.commit()
}
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {
}
})
}
@SuppressLint("ApplySharedPref")
fun getCurrentWeather(context: Context, location: Location) {
val SP: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
try {
val config = WeatherConfig()
config.unitSystem = WeatherConfig.UNIT_SYSTEM.M
config.lang = "en" // If you want to use english
config.maxResult = 1 // Max number of cities retrieved
config.numDays = 1 // Max num of days in the forecast
config.ApiKey = "43e744ad8ff91b09ea62dbc7d0e7c1dd";
val client = WeatherClient.ClientBuilder().attach(context)
.httpClient(com.survivingwithandroid.weather.lib.client.volley.WeatherClientDefault::class.java)
.provider(OpenweathermapProviderType())
.config(config)
.build()
client.getCurrentCondition(WeatherRequest(location.longitude, location.latitude), object : WeatherClient.WeatherEventListener {
@SuppressLint("ApplySharedPref")
override fun onWeatherRetrieved(currentWeather: CurrentWeather) {
Log.d("AW", "TEMP:" + currentWeather.weather.currentCondition.icon);
SP.edit()
.putFloat(Constants.PREF_WEATHER_TEMP, currentWeather.weather.temperature.temp)
.putString(Constants.PREF_WEATHER_ICON, currentWeather.weather.currentCondition.icon)
.commit()
updateWidget(context)
}
@SuppressLint("ApplySharedPref")
override fun onWeatherError(e: WeatherLibException?) {
SP.edit()
.remove(Constants.PREF_WEATHER_TEMP)
.remove(Constants.PREF_WEATHER_ICON)
.commit()
}
@SuppressLint("ApplySharedPref")
override fun onConnectionError(throwable: Throwable?) {
SP.edit()
.remove(Constants.PREF_WEATHER_TEMP)
.remove(Constants.PREF_WEATHER_ICON)
.commit()
}
})
} catch (t: Exception) {
SP.edit()
.remove(Constants.PREF_WEATHER_TEMP)
.remove(Constants.PREF_WEATHER_ICON)
.commit()
}
}
fun showNotification(context: Context) {
val mNotificationManager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
if (!Util.checkGrantedPermission(context, Manifest.permission.READ_CALENDAR)) {
val mBuilder: NotificationCompat.Builder = NotificationCompat.Builder(context, "Settings")
.setSmallIcon(R.drawable.ic_stat_name)
.setPriority(Notification.PRIORITY_MIN)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setContentTitle(context.getString(R.string.notification_title))
.setContentText(context.getString(R.string.notification_subtitle))
.setAutoCancel(true);
val intent: Intent = Intent(context, MainActivity::class.java);
val pi: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pi);
mNotificationManager.notify(0, mBuilder.build());
} else {
mNotificationManager.cancel(0);
}
}
fun openURI(context: Context, url: String) {
try {
val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder();
builder.setToolbarColor(ContextCompat.getColor(context, R.color.colorPrimary));
val customTabsIntent: CustomTabsIntent = builder.build();
customTabsIntent.launchUrl(context, Uri.parse(url));
} catch (e: Exception) {
val legalIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url));
context.startActivity(legalIntent);
}
}
fun share(context: Context) {
val sendIntent = Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT,
"Yep, just another cool widget: https://play.google.com/store/apps/details?id=com.tommasoberlose.anotherwidget");
sendIntent.setType("text/plain");
context.startActivity(Intent.createChooser(sendIntent, context.getString(R.string.action_share)));
}
}

View File

@ -0,0 +1,39 @@
package com.tommasoberlose.anotherwidget.util
import android.Manifest
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.tommasoberlose.anotherwidget.`object`.Constants
class WeatherReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action.equals(Intent.ACTION_BOOT_COMPLETED) || intent.action.equals(Intent.ACTION_INSTALL_PACKAGE) || intent.action.equals(Constants.ACTION_WEATHER_UPDATE)) {
Util.getWeather(context)
}
}
fun setUpdates(context: Context) {
removeUpdates(context)
if (Util.checkGrantedPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)) {
Util.getWeather(context)
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val i = Intent(context, WeatherReceiver::class.java)
i.action = Constants.ACTION_WEATHER_UPDATE
val pi = PendingIntent.getBroadcast(context, 1, i, 0)
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), (1000 * 60 * 60 * 2).toLong(), pi) // 2 hour
}
}
fun removeUpdates(context: Context) {
val intent = Intent(context, WeatherReceiver::class.java)
val sender = PendingIntent.getBroadcast(context, 1, intent, 0)
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.cancel(sender)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners
android:radius="3dp" />
<stroke
android:color="@android:color/white"
android:width="2dp"/>
</shape>
</item>
</selector>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid
android:color="@color/black_30" />
</shape>
</item>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners
android:radius="3dp" />
<solid
android:color="@color/black_30"/>
</shape>
</item>
</selector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:angle="90"
android:startColor="@color/colorNightDark"
android:endColor="@color/colorPrimary"
android:type="linear" />
</shape>
</item>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="108.0"
android:viewportWidth="108.0">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#66FFFFFF"
android:strokeWidth="0.8" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,233 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient_background"
android:orientation="vertical"
tools:context="com.tommasoberlose.anotherwidget.ui.activity.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="48dp"
android:layout_marginLeft="48dp"
android:layout_marginRight="48dp"
android:id="@+id/toolbar"
android:layout_centerHorizontal="true"
android:gravity="center_vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/main_pre_title"
android:alpha="0.6"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:gravity="center_vertical"
style="@style/AnotherWidget.Main.Subtitle"
android:textAllCaps="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:gravity="center_vertical"
style="@style/AnotherWidget.Main.Title"
android:textAllCaps="true"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp"
android:layout_below="@+id/toolbar"
android:gravity="center"
android:layout_above="@+id/menu_container"
android:id="@+id/all_set_container">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Main.Title"
android:gravity="start"
android:textStyle="bold"
android:text="@string/all_set_title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Main.Description"
android:alpha="0.9"
android:fontFamily="sans-serif"
android:text="@string/all_set_subtitle"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Main.Button.Dark"
android:id="@+id/action_github"
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:text="@string/all_set_btn"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone"
android:id="@+id/no_calendar_permission_container"
android:orientation="vertical">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="14dp"
android:tint="@android:color/white"
android:background="@drawable/circle_background"
android:src="@drawable/ic_action_calendar"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Main.Title"
android:paddingTop="16dp"
android:paddingRight="32dp"
android:paddingLeft="32dp"
android:text="@string/title_permission_calendar"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Main.Description"
android:paddingBottom="32dp"
android:paddingRight="32dp"
android:paddingLeft="32dp"
android:text="@string/description_permission_calendar"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Main.Button"
android:id="@+id/request_calendar"
android:text="@string/button_request_permission"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:id="@+id/no_location_permission_container"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="14dp"
android:tint="@android:color/white"
android:background="@drawable/circle_background"
android:src="@drawable/ic_action_location"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Main.Title"
android:paddingTop="16dp"
android:paddingRight="32dp"
android:paddingLeft="32dp"
android:text="@string/title_permission_location"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Main.Description"
android:paddingBottom="32dp"
android:paddingRight="32dp"
android:paddingLeft="32dp"
android:text="@string/description_permission_location"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Main.Button"
android:id="@+id/request_location"
android:text="@string/button_request_permission"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:baselineAligned="false"
android:id="@+id/menu_container"
android:background="@color/black_10"
android:layout_alignParentBottom="true">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:id="@+id/action_share"
android:orientation="vertical">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:padding="2dp"
android:layout_marginTop="8dp"
android:src="@drawable/ic_action_share"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/action_share"
style="@style/AnotherWidget.Main.Button.TabBar"
android:background="@android:color/transparent"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:id="@+id/action_rate"
android:orientation="vertical">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:padding="2dp"
android:layout_marginTop="8dp"
android:src="@drawable/ic_action_rate"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/action_rate"
style="@style/AnotherWidget.Main.Button.TabBar"
android:background="@android:color/transparent"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:gravity="center"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:id="@+id/action_support"
android:orientation="vertical">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:padding="2dp"
android:layout_marginTop="8dp"
android:src="@drawable/ic_action_gift"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/action_support"
style="@style/AnotherWidget.Main.Button.TabBar"
android:background="@android:color/transparent"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,106 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main_layout">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="horizontal"
android:id="@+id/empty_layout">
<TextView
android:id="@+id/empty_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
style="@style/AnotherWidget.Title" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:id="@+id/weather"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="@string/divider"
style="@style/AnotherWidget.Subtitle"/>
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:id="@+id/empty_weather_icon"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:src="@drawable/clear_night"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Date.Big"
android:id="@+id/temp"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
android:visibility="gone"
android:id="@+id/calendar_layout"
android:gravity="center">
<TextView
android:id="@+id/next_event"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Title" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<ImageView
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="4dp"
android:layout_marginStart="4dp"
android:src="@drawable/ic_action_calendar"/>
<TextView
android:id="@+id/next_event_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Subtitle" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:id="@+id/calendar_weather">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="@string/divider"
style="@style/AnotherWidget.Subtitle"/>
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:id="@+id/weather_icon"
android:src="@drawable/clear_night"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Date"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:id="@+id/calendar_temp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="|"
style="@style/AnotherWidget.Subtitle"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AnotherWidget.Date"
android:id="@+id/temp"/>
</LinearLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/gradient_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/gradient_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Some files were not shown because too many files have changed in this diff Show More