[Widgets] Implement new Notifications widget.

This commit is contained in:
Kuba Szczodrzyński 2020-01-06 22:26:54 +01:00
parent 7b97ef316d
commit 878de34546
30 changed files with 457 additions and 603 deletions

View File

@ -25,10 +25,10 @@
-keep class pl.szczodrzynski.edziennik.data.db.entity.Event { *; } -keep class pl.szczodrzynski.edziennik.data.db.entity.Event { *; }
-keep class pl.szczodrzynski.edziennik.data.db.full.EventFull { *; } -keep class pl.szczodrzynski.edziennik.data.db.full.EventFull { *; }
-keep class pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel { *; } -keep class pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel { *; }
-keepclassmembers class pl.szczodrzynski.edziennik.widgets.WidgetConfig { public *; } -keepclassmembers class pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig { public *; }
-keepnames class pl.szczodrzynski.edziennik.WidgetTimetable -keepnames class pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider
-keepnames class pl.szczodrzynski.edziennik.notifications.WidgetNotifications -keepnames class pl.szczodrzynski.edziennik.ui.widgets.notifications.WidgetNotificationsProvider
-keepnames class pl.szczodrzynski.edziennik.luckynumber.WidgetLuckyNumber -keepnames class pl.szczodrzynski.edziennik.widgets.luckynumber.WidgetLuckyNumber
-keep class .R -keep class .R
-keep class **.R$* { -keep class **.R$* {

View File

@ -3,6 +3,17 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="pl.szczodrzynski.edziennik"> package="pl.szczodrzynski.edziennik">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application <application
android:name=".App" android:name=".App"
android:allowBackup="true" android:allowBackup="true"
@ -15,12 +26,16 @@
android:theme="@style/AppTheme.Dark" android:theme="@style/AppTheme.Dark"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
tools:ignore="UnusedAttribute"> tools:ignore="UnusedAttribute">
<activity
android:name=".ui.modules.login.LoginLibrusCaptchaActivity" <!-- __ __ _ _ _ _ _
android:theme="@android:style/Theme.Dialog" | \/ | (_) /\ | | (_) (_) |
android:excludeFromRecents="true"/> | \ / | __ _ _ _ __ / \ ___| |_ ___ ___| |_ _ _
<activity | |\/| |/ _` | | '_ \ / /\ \ / __| __| \ \ / / | __| | | |
android:name=".MainActivity" | | | | (_| | | | | | / ____ \ (__| |_| |\ V /| | |_| |_| |
|_| |_|\__,_|_|_| |_| /_/ \_\___|\__|_| \_/ |_|\__|\__, |
__/ |
|___/ -->
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTop" android:launchMode="singleTop"
@ -32,58 +47,7 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".ui.modules.feedback.FeedbackActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:label="@string/app_name"
android:theme="@style/AppTheme" />
<activity
android:name=".ui.modules.login.LoginActivity"
android:configChanges="orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/AppTheme.Light" />
<activity
android:name=".ui.modules.intro.ChangelogIntroActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name"
android:theme="@style/Theme.Intro" />
<!--
______ _ _
| ____(_) | |
| |__ _ _ __ ___| |__ __ _ ___ ___
| __| | | '__/ _ \ '_ \ / _` / __|/ _ \
| | | | | | __/ |_) | (_| \__ \ __/
|_| |_|_| \___|_.__/ \__,_|___/\___/
-->
<activity
android:name=".ui.modules.base.CrashActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:process=":error_activity"
android:theme="@style/DeadTheme" />
<!--
_____ _ _ _ _ _
/ ____| | | | | (_) (_) |
| | _ __ __ _ ___| |__ __ _ ___| |_ ___ ___| |_ _ _
| | | '__/ _` / __| '_ \ / _` |/ __| __| \ \ / / | __| | | |
| |____| | | (_| \__ \ | | | | (_| | (__| |_| |\ V /| | |_| |_| |
\_____|_| \__,_|___/_| |_| \__,_|\___|\__|_| \_/ |_|\__|\__, |
__/ |
|___/
-->
<activity
android:name=".ui.modules.base.CrashGtfoActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:theme="@style/DeadTheme" />
<activity
android:name=".widgets.WidgetConfigActivity"
android:configChanges="orientation|keyboardHidden"
android:excludeFromRecents="true"
android:noHistory="true"
android:theme="@style/AppTheme.NoDisplay">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<!-- <!--
__ ___ _ _ __ ___ _ _
\ \ / (_) | | | | \ \ / (_) | | | |
@ -92,68 +56,36 @@
\ /\ / | | (_| | (_| | __/ |_ \__ \ \ /\ / | | (_| | (_| | __/ |_ \__ \
\/ \/ |_|\__,_|\__, |\___|\__||___/ \/ \/ |_|\__,_|\__, |\___|\__||___/
__/ | __/ |
|_ |___/
--> -->
<activity android:name=".widgets.timetable.LessonDialogActivity" <activity android:name=".ui.widgets.WidgetConfigActivity"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:noHistory="true" android:noHistory="true"
android:theme="@style/AppTheme.NoDisplay" /> android:theme="@style/AppTheme.NoDisplay">
<activity <intent-filter>
android:name=".ui.modules.settings.SettingsLicenseActivity" <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
android:configChanges="orientation|keyboardHidden" </intent-filter>
android:theme="@style/AppTheme" /> </activity>
<activity <!-- TIMETABLE -->
android:name="com.theartofdev.edmodo.cropper.CropImageActivity" <receiver android:name=".ui.widgets.timetable.WidgetTimetableProvider"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/Base.Theme.AppCompat" />
<activity
android:name=".ui.modules.webpush.WebPushConfigActivity"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/AppTheme.Dark" />
<activity
android:name=".ui.modules.home.CounterActivity"
android:theme="@style/AppTheme.Black" />
<activity android:name=".ui.modules.webpush.QrScannerActivity" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<!--
_____ _ _
| __ \ (_) | |
| |__) | __ _____ ___ __| | ___ _ __ ___
| ___/ '__/ _ \ \ / / |/ _` |/ _ \ '__/ __|
| | | | | (_) \ V /| | (_| | __/ | \__ \
|_| |_| \___/ \_/ |_|\__,_|\___|_| |___/
-->
<receiver
android:name=".WidgetTimetable"
android:label="@string/widget_timetable_title"> android:label="@string/widget_timetable_title">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/widget_timetable_info" /> android:resource="@xml/widget_timetable_info" />
</receiver> </receiver>
<!-- <service android:name=".ui.widgets.timetable.WidgetTimetableService"
____ _ _ android:permission="android.permission.BIND_REMOTEVIEWS" />
| _ \ | | (_) <activity android:name=".ui.widgets.LessonDialogActivity"
| |_) | ___ ___ | |_ _ __ ___ ___ ___ ___ _____ _ __ android:configChanges="orientation|keyboardHidden"
| _ < / _ \ / _ \| __| | '__/ _ \/ __/ _ \ \ \ / / _ \ '__| android:excludeFromRecents="true"
| |_) | (_) | (_) | |_ | | | __/ (_| __/ |\ V / __/ | android:noHistory="true"
|____/ \___/ \___/ \__| |_| \___|\___\___|_| \_/ \_____| android:theme="@style/AppTheme.NoDisplay" />
--> <!-- NOTIFICATIONS -->
<receiver <receiver android:name=".ui.widgets.notifications.WidgetNotificationsProvider"
android:name=".widgets.notifications.WidgetNotifications"
android:label="@string/widget_notifications_title"> android:label="@string/widget_notifications_title">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -163,8 +95,10 @@
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/widget_notifications_info" /> android:resource="@xml/widget_notifications_info" />
</receiver> </receiver>
<receiver <service android:name=".ui.widgets.notifications.WidgetNotificationsService"
android:name=".widgets.luckynumber.WidgetLuckyNumber" android:permission="android.permission.BIND_REMOTEVIEWS" />
<!-- LUCKY NUMBER -->
<receiver android:name=".widgets.luckynumber.WidgetLuckyNumber"
android:label="@string/widget_lucky_number_title"> android:label="@string/widget_lucky_number_title">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -174,8 +108,58 @@
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/widget_lucky_number_info" /> android:resource="@xml/widget_lucky_number_info" />
</receiver> </receiver>
<receiver
android:name=".receivers.UserPresentReceiver" <!-- _ _ _ _ _
/\ | | (_) (_) | (_)
/ \ ___| |_ ___ ___| |_ _ ___ ___
/ /\ \ / __| __| \ \ / / | __| |/ _ \/ __|
/ ____ \ (__| |_| |\ V /| | |_| | __/\__ \
/_/ \_\___|\__|_| \_/ |_|\__|_|\___||___/
-->
<activity android:name=".ui.modules.base.CrashActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:process=":error_activity"
android:theme="@style/DeadTheme" />
<activity android:name=".ui.modules.base.CrashGtfoActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:theme="@style/DeadTheme" />
<activity android:name=".ui.modules.intro.ChangelogIntroActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name"
android:theme="@style/Theme.Intro" />
<activity android:name=".ui.modules.login.LoginActivity"
android:configChanges="orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/AppTheme.Light" />
<activity android:name=".ui.modules.login.LoginLibrusCaptchaActivity"
android:theme="@android:style/Theme.Dialog"
android:excludeFromRecents="true"/>
<activity android:name=".ui.modules.home.CounterActivity"
android:theme="@style/AppTheme.Black" />
<activity android:name=".ui.modules.feedback.FeedbackActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:label="@string/app_name"
android:theme="@style/AppTheme" />
<activity android:name=".ui.modules.settings.SettingsLicenseActivity"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/AppTheme" />
<activity android:name=".ui.modules.webpush.WebPushConfigActivity"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/AppTheme.Dark" />
<activity android:name=".ui.modules.webpush.QrScannerActivity" />
<activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/Base.Theme.AppCompat" />
<!-- _____ _
| __ \ (_)
| |__) |___ ___ ___ ___ _____ _ __ ___
| _ // _ \/ __/ _ \ \ \ / / _ \ '__/ __|
| | \ \ __/ (_| __/ |\ V / __/ | \__ \
|_| \_\___|\___\___|_| \_/ \___|_| |___/
-->
<receiver android:name=".receivers.UserPresentReceiver"
android:enabled="true"> android:enabled="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.USER_PRESENT" /> <action android:name="android.intent.action.USER_PRESENT" />
@ -188,54 +172,53 @@
<action android:name="android.intent.action.QUICKBOOT_POWERON" /> <action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name=".sync.FirebaseBroadcastReceiver"
<receiver
android:name=".sync.FirebaseBroadcastReceiver"
android:exported="true" android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND"> android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter> <intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" /> <action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name=".receivers.SzkolnyReceiver"
<receiver
android:name=".receivers.SzkolnyReceiver"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="pl.szczodrzynski.edziennik.SZKOLNY_MAIN" /> <action android:name="pl.szczodrzynski.edziennik.SZKOLNY_MAIN" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<service <!-- _____ _
android:name=".sync.MyFirebaseMessagingService" / ____| (_)
| (___ ___ _ ____ ___ ___ ___ ___
\___ \ / _ \ '__\ \ / / |/ __/ _ \/ __|
____) | __/ | \ V /| | (_| __/\__ \
|_____/ \___|_| \_/ |_|\___\___||___/
-->
<service android:name=".sync.MyFirebaseMessagingService"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" /> <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
<action android:name="com.google.firebase.MESSAGING_EVENT" /> <action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter> </intent-filter>
</service> </service>
<service
android:name=".widgets.timetable.WidgetTimetableService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<service
android:name=".widgets.notifications.WidgetNotificationsService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<service android:name=".receivers.BootReceiver$NotificationActionService" /> <service android:name=".receivers.BootReceiver$NotificationActionService" />
<service android:name=".Notifier$GetDataRetryService" /> <service android:name=".Notifier$GetDataRetryService" />
<service android:name=".data.api.ApiService" />
<service android:name="pl.szczodrzynski.edziennik.data.api.ApiService" /> <!--
_____ _ _
| __ \ (_) | |
| |__) | __ _____ ___ __| | ___ _ __ ___
| ___/ '__/ _ \ \ / / |/ _` |/ _ \ '__/ __|
| | | | | (_) \ V /| | (_| | __/ | \__ \
|_| |_| \___/ \_/ |_|\__,_|\___|_| |___/
-->
<provider android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application> </application>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest> </manifest>

View File

@ -6,6 +6,7 @@ import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Resources import android.content.res.Resources
import android.database.Cursor
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter import android.graphics.PorterDuffColorFilter
import android.graphics.Typeface import android.graphics.Typeface
@ -26,6 +27,9 @@ import android.widget.CompoundButton
import android.widget.TextView import android.widget.TextView
import androidx.annotation.* import androidx.annotation.*
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.database.getIntOrNull
import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull
import androidx.core.util.forEach import androidx.core.util.forEach
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
@ -938,3 +942,7 @@ fun Context.getNotificationTitle(type: Int): String {
else -> R.string.notification_type_general else -> R.string.notification_type_general
}) })
} }
fun Cursor?.getString(columnName: String) = this?.getStringOrNull(getColumnIndex(columnName))
fun Cursor?.getInt(columnName: String) = this?.getIntOrNull(getColumnIndex(columnName))
fun Cursor?.getLong(columnName: String) = this?.getLongOrNull(getColumnIndex(columnName))

View File

@ -4,6 +4,7 @@
package pl.szczodrzynski.edziennik.config package pl.szczodrzynski.edziennik.config
import com.google.gson.JsonObject
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -74,6 +75,11 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
get() { mRunSync = mRunSync ?: values.get("runSync", false); return mRunSync ?: false } get() { mRunSync = mRunSync ?: values.get("runSync", false); return mRunSync ?: false }
set(value) { set("runSync", value); mRunSync = value } set(value) { set("runSync", value); mRunSync = value }
private var mWidgetConfigs: JsonObject? = null
var widgetConfigs: JsonObject
get() { mWidgetConfigs = mWidgetConfigs ?: values.get("widgetConfigs", JsonObject()); return mWidgetConfigs ?: JsonObject() }
set(value) { set("widgetConfigs", value); mWidgetConfigs = value }
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow() private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf() private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
init { init {

View File

@ -10,38 +10,14 @@ import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.interfaces.EndpointCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EndpointCallback
import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Announcement import pl.szczodrzynski.edziennik.data.db.entity.*
import pl.szczodrzynski.edziennik.data.db.entity.EndpointTimer
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.AttendanceType
import pl.szczodrzynski.edziennik.data.db.entity.Classroom
import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.data.db.entity.EventType
import pl.szczodrzynski.edziennik.data.db.entity.Grade
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Notice
import pl.szczodrzynski.edziennik.data.db.entity.NoticeType
import pl.szczodrzynski.edziennik.data.db.entity.Notification
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Subject
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.entity.TeacherAbsence
import pl.szczodrzynski.edziennik.data.db.entity.TeacherAbsenceType
import pl.szczodrzynski.edziennik.data.db.entity.Team
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.data.db.entity.LibrusLesson
import pl.szczodrzynski.edziennik.singleOrNull import pl.szczodrzynski.edziennik.singleOrNull
import pl.szczodrzynski.edziennik.toSparseArray import pl.szczodrzynski.edziennik.toSparseArray
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.values import pl.szczodrzynski.edziennik.values
import java.io.InterruptedIOException import java.io.InterruptedIOException
import java.net.ConnectException
import java.net.SocketTimeoutException import java.net.SocketTimeoutException
import java.net.UnknownHostException import java.net.UnknownHostException
import javax.net.ssl.SSLException import javax.net.ssl.SSLException
@ -390,7 +366,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
apiError.errorCode = when (apiError.throwable) { apiError.errorCode = when (apiError.throwable) {
is UnknownHostException -> ERROR_REQUEST_FAILURE_HOSTNAME_NOT_FOUND is UnknownHostException -> ERROR_REQUEST_FAILURE_HOSTNAME_NOT_FOUND
is SSLException -> ERROR_REQUEST_FAILURE_SSL_ERROR is SSLException -> ERROR_REQUEST_FAILURE_SSL_ERROR
is InterruptedIOException -> ERROR_REQUEST_FAILURE_NO_INTERNET is InterruptedIOException, is ConnectException -> ERROR_REQUEST_FAILURE_NO_INTERNET
is SocketTimeoutException -> ERROR_REQUEST_FAILURE_TIMEOUT is SocketTimeoutException -> ERROR_REQUEST_FAILURE_TIMEOUT
else -> else ->
if (apiError.errorCode == ERROR_REQUEST_FAILURE) if (apiError.errorCode == ERROR_REQUEST_FAILURE)

View File

@ -4,6 +4,7 @@
package pl.szczodrzynski.edziennik.data.db.dao package pl.szczodrzynski.edziennik.data.db.dao
import android.database.Cursor
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
@ -36,4 +37,7 @@ interface NotificationDao {
@Query("UPDATE notifications SET posted = 1 WHERE posted = 0") @Query("UPDATE notifications SET posted = 1 WHERE posted = 0")
fun setAllPosted() fun setAllPosted()
@Query("SELECT * FROM notifications ORDER BY addedDate DESC")
fun getAllCursor(): Cursor
} }

View File

@ -13,6 +13,10 @@ import pl.szczodrzynski.edziennik.data.api.events.requests.TaskCancelRequest
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
class SzkolnyReceiver : BroadcastReceiver() { class SzkolnyReceiver : BroadcastReceiver() {
companion object {
const val ACTION = "pl.szczodrzynski.edziennik.SZKOLNY_MAIN"
}
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
context ?: return context ?: return
when (intent?.extras?.getString("task", null)) { when (intent?.extras?.getString("task", null)) {

View File

@ -6,7 +6,7 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import pl.szczodrzynski.edziennik.WidgetTimetable; import pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider;
public class UserPresentReceiver extends BroadcastReceiver { public class UserPresentReceiver extends BroadcastReceiver {
@Override @Override
@ -14,12 +14,12 @@ public class UserPresentReceiver extends BroadcastReceiver {
if (intent.getAction() != null) { if (intent.getAction() != null) {
if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) { if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
//Toast.makeText(context, "User is present", Toast.LENGTH_SHORT).show(); //Toast.makeText(context, "User is present", Toast.LENGTH_SHORT).show();
Intent widgetIntent = new Intent(context, WidgetTimetable.class); Intent widgetIntent = new Intent(context, WidgetTimetableProvider.class);
widgetIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); widgetIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
// Use an array and EXTRA_APPWIDGET_IDS instead of AppWidgetManager.EXTRA_APPWIDGET_ID, // Use an array and EXTRA_APPWIDGET_IDS instead of AppWidgetManager.EXTRA_APPWIDGET_ID,
// since it seems the onUpdate() is only fired on that: // since it seems the onUpdate() is only fired on that:
int[] ids = AppWidgetManager.getInstance(context) int[] ids = AppWidgetManager.getInstance(context)
.getAppWidgetIds(new ComponentName(context, WidgetTimetable.class)); .getAppWidgetIds(new ComponentName(context, WidgetTimetableProvider.class));
widgetIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids); widgetIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
context.sendBroadcast(widgetIntent); context.sendBroadcast(widgetIntent);
} }

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-11-14. * Copyright (c) Kuba Szczodrzyński 2019-11-14.
*/ */
package pl.szczodrzynski.edziennik.widgets.timetable package pl.szczodrzynski.edziennik.ui.widgets
import android.content.Intent import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT import android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT

View File

@ -1,4 +1,8 @@
package pl.szczodrzynski.edziennik.widgets; /*
* Copyright (c) Kuba Szczodrzyński 2020-1-6.
*/
package pl.szczodrzynski.edziennik.ui.widgets;
public class WidgetConfig { public class WidgetConfig {
public int profileId = -1; public int profileId = -1;

View File

@ -1,4 +1,8 @@
package pl.szczodrzynski.edziennik.widgets; /*
* Copyright (c) Kuba Szczodrzyński 2020-1-6.
*/
package pl.szczodrzynski.edziennik.ui.widgets;
import android.app.Activity; import android.app.Activity;
import android.app.WallpaperManager; import android.app.WallpaperManager;
@ -15,16 +19,17 @@ import android.widget.SeekBar;
import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.simplelist.MaterialSimpleListAdapter; import com.afollestad.materialdialogs.simplelist.MaterialSimpleListAdapter;
import com.afollestad.materialdialogs.simplelist.MaterialSimpleListItem; import com.afollestad.materialdialogs.simplelist.MaterialSimpleListItem;
import com.google.gson.JsonObject;
import java.util.List; import java.util.List;
import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.WidgetTimetable;
import pl.szczodrzynski.edziennik.data.db.entity.Profile; import pl.szczodrzynski.edziennik.data.db.entity.Profile;
import pl.szczodrzynski.edziennik.databinding.DialogWidgetConfigBinding; import pl.szczodrzynski.edziennik.databinding.DialogWidgetConfigBinding;
import pl.szczodrzynski.edziennik.ui.widgets.notifications.WidgetNotificationsProvider;
import pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider;
import pl.szczodrzynski.edziennik.widgets.luckynumber.WidgetLuckyNumber; import pl.szczodrzynski.edziennik.widgets.luckynumber.WidgetLuckyNumber;
import pl.szczodrzynski.edziennik.widgets.notifications.WidgetNotifications;
import static pl.szczodrzynski.edziennik.ExtensionsKt.filterOutArchived; import static pl.szczodrzynski.edziennik.ExtensionsKt.filterOutArchived;
@ -130,17 +135,19 @@ public class WidgetConfigActivity extends Activity {
.positiveText(R.string.ok) .positiveText(R.string.ok)
.negativeText(R.string.cancel) .negativeText(R.string.cancel)
.onPositive(((dialog1, which) -> { .onPositive(((dialog1, which) -> {
app.appConfig.widgetTimetableConfigs.put(mAppWidgetId, new WidgetConfig(profileId, bigStyle, darkTheme, opacity)); WidgetConfig config = new WidgetConfig(profileId, bigStyle, darkTheme, opacity);
app.saveConfig("widgetTimetableConfigs"); JsonObject configs = app.config.getWidgetConfigs();
configs.add(Integer.toString(mAppWidgetId), app.gson.toJsonTree(config));
app.config.setWidgetConfigs(configs);
Intent refreshIntent; Intent refreshIntent;
switch (widgetType) { switch (widgetType) {
default: default:
case WIDGET_TIMETABLE: case WIDGET_TIMETABLE:
refreshIntent = new Intent(app.getContext(), WidgetTimetable.class); refreshIntent = new Intent(app.getContext(), WidgetTimetableProvider.class);
break; break;
case WIDGET_NOTIFICATIONS: case WIDGET_NOTIFICATIONS:
refreshIntent = new Intent(app.getContext(), WidgetNotifications.class); refreshIntent = new Intent(app.getContext(), WidgetNotificationsProvider.class);
break; break;
case WIDGET_LUCKY_NUMBER: case WIDGET_LUCKY_NUMBER:
refreshIntent = new Intent(app.getContext(), WidgetLuckyNumber.class); refreshIntent = new Intent(app.getContext(), WidgetLuckyNumber.class);

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-6.
*/
package pl.szczodrzynski.edziennik.ui.widgets.notifications
import android.content.Intent
import android.database.Cursor
import android.os.Binder
import android.widget.AdapterView
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import com.google.gson.JsonParser
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Notification
import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig
import pl.szczodrzynski.edziennik.utils.models.Date
class WidgetNotificationsFactory(val app: App, val config: WidgetConfig) : RemoteViewsService.RemoteViewsFactory {
companion object {
private const val TAG = "WidgetNotificationsFactory"
}
private var cursor: Cursor? = null
override fun onDataSetChanged() {
cursor?.close()
Binder.clearCallingIdentity().let {
cursor = app.db.notificationDao().getAllCursor()
Binder.restoreCallingIdentity(it)
}
}
override fun getViewAt(position: Int): RemoteViews? {
if (position == AdapterView.INVALID_POSITION || cursor?.moveToPosition(position) != true)
return null
val views: RemoteViews = if (config.bigStyle) {
RemoteViews(app.packageName, if (config.darkTheme) R.layout.row_widget_notifications_dark_big_item else R.layout.row_widget_notifications_big_item)
} else {
RemoteViews(app.packageName, if (config.darkTheme) R.layout.row_widget_notifications_dark_item else R.layout.row_widget_notifications_item)
}
val notification = cursor?.run {
Notification(
getInt("id") ?: 0,
getString("title") ?: "",
getString("text") ?: "",
getInt("type") ?: 0,
getInt("profileId"),
getString("profileName"),
getInt("posted") == 1,
getInt("viewId"),
getString("extras")?.let { JsonParser().parse(it).asJsonObject },
getLong("addedDate") ?: System.currentTimeMillis()
)
} ?: return views
views.apply {
setTextViewText(R.id.widgetNotificationsTitle,
app.getString(R.string.widget_notifications_title_format, notification.title, app.getNotificationTitle(notification.type)))
setTextViewText(R.id.widgetNotificationsText, notification.text)
setTextViewText(R.id.widgetNotificationsDate, Date.fromMillis(notification.addedDate).formattedString)
setOnClickFillInIntent(R.id.widgetNotificationsRoot, Intent().also { notification.fillIntent(it) })
}
return views
}
override fun getItemId(position: Int): Long = if (cursor?.moveToPosition(position) == true)
cursor?.getLong("id") ?: position.toLong() else position.toLong()
override fun getCount() = cursor?.count ?: 0
override fun onCreate() {}
override fun getLoadingView() = null
override fun hasStableIds() = true
override fun getViewTypeCount() = 1
override fun onDestroy() = cursor?.close() ?: Unit
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-6.
*/
package pl.szczodrzynski.edziennik.ui.widgets.notifications
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.view.View
import android.widget.RemoteViews
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.receivers.SzkolnyReceiver
import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig
class WidgetNotificationsProvider : AppWidgetProvider() {
companion object {
private const val TAG = "WidgetNotificationsProvider"
}
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
val app = context.applicationContext as App
val widgetConfigs = app.config.widgetConfigs
for (appWidgetId in appWidgetIds) {
val config = widgetConfigs.getJsonObject(appWidgetId.toString())?.let { app.gson.fromJson(it, WidgetConfig::class.java) } ?: continue
val iconSize = if (config.bigStyle) 24 else 16
val views: RemoteViews = if (config.bigStyle) {
RemoteViews(app.packageName, if (config.darkTheme) R.layout.widget_notifications_dark_big else R.layout.widget_notifications_big)
} else {
RemoteViews(app.packageName, if (config.darkTheme) R.layout.widget_notifications_dark else R.layout.widget_notifications)
}
val syncIntent = Intent(SzkolnyReceiver.ACTION)
syncIntent.putExtra("task", "SyncRequest")
val syncPendingIntent = PendingIntent.getBroadcast(context, 0, syncIntent, 0)
views.setOnClickPendingIntent(R.id.widgetNotificationsSync, syncPendingIntent)
views.setImageViewBitmap(
R.id.widgetNotificationsSync,
IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
.colorInt(Color.WHITE)
.sizeDp(iconSize)
.toBitmap()
)
views.setViewVisibility(R.id.widgetNotificationsLoading, View.GONE)
val listIntent = Intent(context, WidgetNotificationsService::class.java)
listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
listIntent.putExtra("config", app.gson.toJson(config))
listIntent.data = Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME))
views.setRemoteAdapter(R.id.widgetNotificationsListView, listIntent)
val itemIntent = Intent(context, MainActivity::class.java)
itemIntent.action = Intent.ACTION_MAIN
val itemPendingIntent = PendingIntent.getActivity(context, 0, itemIntent, 0)
views.setPendingIntentTemplate(R.id.widgetNotificationsListView, itemPendingIntent)
val headerIntent = Intent(context, MainActivity::class.java)
headerIntent.action = Intent.ACTION_MAIN
headerIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_NOTIFICATIONS)
val headerPendingIntent = PendingIntent.getActivity(context, 0, headerIntent, 0)
views.setOnClickPendingIntent(R.id.widgetNotificationsHeader, headerPendingIntent)
appWidgetManager.updateAppWidget(appWidgetId, views)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetNotificationsListView)
}
}
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
val app = context.applicationContext as App
val widgetConfigs = app.config.widgetConfigs
appWidgetIds.forEach {
widgetConfigs.remove(it.toString())
}
app.config.widgetConfigs = widgetConfigs
}
}

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-6.
*/
package pl.szczodrzynski.edziennik.ui.widgets.notifications
import android.content.Intent
import android.widget.RemoteViewsService
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig
class WidgetNotificationsService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
val app = application as App
val config = intent.getStringExtra("config")?.let { app.gson.fromJson(it, WidgetConfig::class.java) }
return WidgetNotificationsFactory(app, config ?: WidgetConfig(-1))
}
}

View File

@ -1,4 +1,8 @@
package pl.szczodrzynski.edziennik.widgets.timetable; /*
* Copyright (c) Kuba Szczodrzyński 2020-1-6.
*/
package pl.szczodrzynski.edziennik.ui.widgets.timetable;
import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManager;
import android.content.ComponentName; import android.content.ComponentName;
@ -28,14 +32,13 @@ import com.mikepenz.iconics.typeface.library.community.material.CommunityMateria
import java.util.List; import java.util.List;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.WidgetTimetable;
import pl.szczodrzynski.edziennik.utils.models.Date; import pl.szczodrzynski.edziennik.utils.models.Date;
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel; import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel;
import pl.szczodrzynski.edziennik.utils.models.Time; import pl.szczodrzynski.edziennik.utils.models.Time;
import static android.util.TypedValue.COMPLEX_UNIT_SP; import static android.util.TypedValue.COMPLEX_UNIT_SP;
public class WidgetTimetableListProvider implements RemoteViewsService.RemoteViewsFactory { public class WidgetTimetableFactory implements RemoteViewsService.RemoteViewsFactory {
private static final String TAG = "WidgetTimetableProvider"; private static final String TAG = "WidgetTimetableProvider";
private Context context; private Context context;
@ -44,7 +47,7 @@ public class WidgetTimetableListProvider implements RemoteViewsService.RemoteVie
private static boolean triedToReload = false; private static boolean triedToReload = false;
//For obtaining the activity's context and intent //For obtaining the activity's context and intent
public WidgetTimetableListProvider(Context context, Intent intent) { public WidgetTimetableFactory(Context context, Intent intent) {
this.context = context; this.context = context;
this.appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0); this.appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0);
// executed only ONCE // executed only ONCE
@ -65,7 +68,7 @@ public class WidgetTimetableListProvider implements RemoteViewsService.RemoteVie
public void onDataSetChanged() { public void onDataSetChanged() {
// executed EVERY TIME // executed EVERY TIME
Log.d(TAG, "onDataSetChanged for appWidgetId: "+appWidgetId); Log.d(TAG, "onDataSetChanged for appWidgetId: "+appWidgetId);
lessons = WidgetTimetable.Companion.getTimetables() == null ? null : WidgetTimetable.Companion.getTimetables().get(appWidgetId); lessons = WidgetTimetableProvider.Companion.getTimetables() == null ? null : WidgetTimetableProvider.Companion.getTimetables().get(appWidgetId);
} }
@Override @Override
@ -306,11 +309,11 @@ public class WidgetTimetableListProvider implements RemoteViewsService.RemoteVie
// try to reload the widget // try to reload the widget
// only once // only once
triedToReload = true; triedToReload = true;
Intent intent = new Intent(context, WidgetTimetable.class); Intent intent = new Intent(context, WidgetTimetableProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
// Use an array and EXTRA_APPWIDGET_IDS instead of AppWidgetManager.EXTRA_APPWIDGET_ID, // Use an array and EXTRA_APPWIDGET_IDS instead of AppWidgetManager.EXTRA_APPWIDGET_ID,
// since it seems the onUpdate() is only fired on that: // since it seems the onUpdate() is only fired on that:
int[] ids = AppWidgetManager.getInstance(context).getAppWidgetIds(new ComponentName(context, WidgetTimetable.class)); int[] ids = AppWidgetManager.getInstance(context).getAppWidgetIds(new ComponentName(context, WidgetTimetableProvider.class));
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }

View File

@ -1,4 +1,8 @@
package pl.szczodrzynski.edziennik /*
* Copyright (c) Kuba Szczodrzyński 2020-1-6.
*/
package pl.szczodrzynski.edziennik.ui.widgets.timetable
import android.app.PendingIntent import android.app.PendingIntent
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
@ -21,20 +25,50 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.iconics.utils.sizeDp
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
import pl.szczodrzynski.edziennik.data.db.entity.Event.TYPE_HOMEWORK import pl.szczodrzynski.edziennik.data.db.entity.Event.TYPE_HOMEWORK
import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.ui.widgets.LessonDialogActivity
import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel
import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.models.Time
import pl.szczodrzynski.edziennik.utils.models.Week import pl.szczodrzynski.edziennik.utils.models.Week
import pl.szczodrzynski.edziennik.widgets.WidgetConfig
import pl.szczodrzynski.edziennik.widgets.timetable.LessonDialogActivity
import pl.szczodrzynski.edziennik.widgets.timetable.WidgetTimetableService
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
class WidgetTimetable : AppWidgetProvider() { class WidgetTimetableProvider : AppWidgetProvider() {
companion object {
const val ACTION_SYNC_DATA = "ACTION_SYNC_DATA"
private const val TAG = "WidgetTimetable"
var timetables: SparseArray<List<ItemWidgetTimetableModel>>? = null
fun getPendingSelfIntent(context: Context, action: String): PendingIntent {
val intent = Intent(context, WidgetTimetableProvider::class.java)
intent.action = action
return getPendingSelfIntent(context, intent)
}
fun getPendingSelfIntent(context: Context, intent: Intent): PendingIntent {
return PendingIntent.getBroadcast(context, 0, intent, 0)
}
fun drawableToBitmap(drawable: Drawable): Bitmap {
if (drawable is BitmapDrawable) {
return drawable.bitmap
}
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
}
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
if (ACTION_SYNC_DATA == intent.action) { if (ACTION_SYNC_DATA == intent.action) {
@ -46,12 +80,12 @@ class WidgetTimetable : AppWidgetProvider() {
private val ignoreCancelled = true private val ignoreCancelled = true
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
val thisWidget = ComponentName(context, WidgetTimetable::class.java) val thisWidget = ComponentName(context, WidgetTimetableProvider::class.java)
timetables = SparseArray() timetables = SparseArray()
//timetables.clear();
val app = context.applicationContext as App val app = context.applicationContext as App
val widgetConfigs = app.config.widgetConfigs
var bellSyncDiffMillis: Long = 0 var bellSyncDiffMillis: Long = 0
app.config.timetable.bellSyncDiff?.let { app.config.timetable.bellSyncDiff?.let {
@ -63,37 +97,32 @@ class WidgetTimetable : AppWidgetProvider() {
val allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget) val allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget)
allWidgetIds?.forEach { appWidgetId -> allWidgetIds?.forEach { appWidgetId ->
var widgetConfig = app.appConfig.widgetTimetableConfigs[appWidgetId] val config = widgetConfigs.getJsonObject(appWidgetId.toString())?.let { app.gson.fromJson(it, WidgetConfig::class.java) } ?: return@forEach
if (widgetConfig == null) {
widgetConfig = WidgetConfig(app.profileFirstId())
app.appConfig.widgetTimetableConfigs[appWidgetId] = widgetConfig
app.appConfig.savePending = true
}
val views = if (widgetConfig.bigStyle) { val views = if (config.bigStyle) {
RemoteViews(context.packageName, if (widgetConfig.darkTheme) R.layout.widget_timetable_dark_big else R.layout.widget_timetable_big) RemoteViews(context.packageName, if (config.darkTheme) R.layout.widget_timetable_dark_big else R.layout.widget_timetable_big)
} else { } else {
RemoteViews(context.packageName, if (widgetConfig.darkTheme) R.layout.widget_timetable_dark else R.layout.widget_timetable) RemoteViews(context.packageName, if (config.darkTheme) R.layout.widget_timetable_dark else R.layout.widget_timetable)
} }
val refreshIntent = Intent(app, WidgetTimetable::class.java) val refreshIntent = Intent(app, WidgetTimetableProvider::class.java)
refreshIntent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE refreshIntent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds) refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
val pendingRefreshIntent = PendingIntent.getBroadcast(context, val refreshPendingIntent = PendingIntent.getBroadcast(context,
0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT) 0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT)
views.setOnClickPendingIntent(R.id.widgetTimetableRefresh, pendingRefreshIntent) views.setOnClickPendingIntent(R.id.widgetTimetableRefresh, refreshPendingIntent)
views.setOnClickPendingIntent(R.id.widgetTimetableSync, getPendingSelfIntent(context, ACTION_SYNC_DATA)) views.setOnClickPendingIntent(R.id.widgetTimetableSync, getPendingSelfIntent(context, ACTION_SYNC_DATA))
views.setImageViewBitmap(R.id.widgetTimetableRefresh, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh) views.setImageViewBitmap(R.id.widgetTimetableRefresh, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh)
.colorInt(Color.WHITE) .colorInt(Color.WHITE)
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap()) .sizeDp(if (config.bigStyle) 24 else 16).toBitmap())
views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline) views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
.colorInt(Color.WHITE) .colorInt(Color.WHITE)
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap()) .sizeDp(if (config.bigStyle) 24 else 16).toBitmap())
prepareAppWidget(app, appWidgetId, views, widgetConfig, bellSyncDiffMillis) prepareAppWidget(app, appWidgetId, views, config, bellSyncDiffMillis)
appWidgetManager.updateAppWidget(appWidgetId, views) appWidgetManager.updateAppWidget(appWidgetId, views)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetTimetableListView) appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetTimetableListView)
@ -329,20 +358,20 @@ class WidgetTimetable : AppWidgetProvider() {
} }
// intent running when the header is clicked // intent running when the header is clicked
val openIntent = Intent(app, MainActivity::class.java) val headerIntent = Intent(app, MainActivity::class.java)
openIntent.action = "android.intent.action.MAIN" headerIntent.action = "android.intent.action.MAIN"
if (!unified) { if (!unified) {
// per-profile widget should redirect to it + correct day // per-profile widget should redirect to it + correct day
profileId?.let { profileId?.let {
openIntent.putExtra("profileId", it) headerIntent.putExtra("profileId", it)
} }
displayingDate?.let { displayingDate?.let {
openIntent.putExtra("timetableDate", it.value) headerIntent.putExtra("timetableDate", it.value)
} }
} }
openIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE) headerIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE)
val pendingOpenIntent = PendingIntent.getActivity(app, appWidgetId, openIntent, 0) val headerPendingIntent = PendingIntent.getActivity(app, appWidgetId, headerIntent, 0)
views.setOnClickPendingIntent(R.id.widgetTimetableHeader, pendingOpenIntent) views.setOnClickPendingIntent(R.id.widgetTimetableHeader, headerPendingIntent)
timetables!!.put(appWidgetId, models) timetables!!.put(appWidgetId, models)
@ -353,55 +382,21 @@ class WidgetTimetable : AppWidgetProvider() {
views.setRemoteAdapter(R.id.widgetTimetableListView, listIntent) views.setRemoteAdapter(R.id.widgetTimetableListView, listIntent)
// create an intent used to display the lesson details dialog // create an intent used to display the lesson details dialog
val intentTemplate = Intent(app, LessonDialogActivity::class.java) val itemIntent = Intent(app, LessonDialogActivity::class.java)
intentTemplate.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK /*or Intent.FLAG_ACTIVITY_CLEAR_TASK*/) itemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK /*or Intent.FLAG_ACTIVITY_CLEAR_TASK*/)
val pendingIntentTimetable = PendingIntent.getActivity(app, appWidgetId, intentTemplate, 0) val itemPendingIntent = PendingIntent.getActivity(app, appWidgetId, itemIntent, 0)
views.setPendingIntentTemplate(R.id.widgetTimetableListView, pendingIntentTimetable) views.setPendingIntentTemplate(R.id.widgetTimetableListView, itemPendingIntent)
if (!unified) if (!unified)
views.setScrollPosition(R.id.widgetTimetableListView, scrollPos) views.setScrollPosition(R.id.widgetTimetableListView, scrollPos)
} }
override fun onEnabled(context: Context) {
// Enter relevant functionality for when the first widget is created
}
override fun onDeleted(context: Context, appWidgetIds: IntArray) { override fun onDeleted(context: Context, appWidgetIds: IntArray) {
val app = context.applicationContext as App val app = context.applicationContext as App
for (appWidgetId in appWidgetIds) { val widgetConfigs = app.config.widgetConfigs
app.appConfig.widgetTimetableConfigs.remove(appWidgetId) appWidgetIds.forEach {
} widgetConfigs.remove(it.toString())
app.saveConfig("widgetTimetableConfigs")
}
companion object {
const val ACTION_SYNC_DATA = "ACTION_SYNC_DATA"
private const val TAG = "WidgetTimetable"
var timetables: SparseArray<List<ItemWidgetTimetableModel>>? = null
fun getPendingSelfIntent(context: Context, action: String): PendingIntent {
val intent = Intent(context, WidgetTimetable::class.java)
intent.action = action
return getPendingSelfIntent(context, intent)
}
fun getPendingSelfIntent(context: Context, intent: Intent): PendingIntent {
return PendingIntent.getBroadcast(context, 0, intent, 0)
}
fun drawableToBitmap(drawable: Drawable): Bitmap {
if (drawable is BitmapDrawable) {
return drawable.bitmap
}
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
} }
app.config.widgetConfigs = widgetConfigs
} }
} }

View File

@ -0,0 +1,15 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-6.
*/
package pl.szczodrzynski.edziennik.ui.widgets.timetable;
import android.content.Intent;
import android.widget.RemoteViewsService;
public class WidgetTimetableService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return (new WidgetTimetableFactory(this.getApplicationContext(), intent));
}
}

View File

@ -8,7 +8,7 @@ import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.widgets.WidgetConfig; import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig;
public class AppConfig { public class AppConfig {

View File

@ -26,7 +26,7 @@ import pl.szczodrzynski.edziennik.MainActivity;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask; import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask;
import pl.szczodrzynski.edziennik.data.db.entity.Profile; import pl.szczodrzynski.edziennik.data.db.entity.Profile;
import pl.szczodrzynski.edziennik.widgets.WidgetConfig; import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig;
import static pl.szczodrzynski.edziennik.utils.Utils.getCellsForSize; import static pl.szczodrzynski.edziennik.utils.Utils.getCellsForSize;

View File

@ -1,171 +0,0 @@
package pl.szczodrzynski.edziennik.widgets.notifications;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.view.View;
import android.widget.RemoteViews;
import com.mikepenz.iconics.IconicsColor;
import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.iconics.IconicsSize;
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.MainActivity;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask;
import pl.szczodrzynski.edziennik.widgets.WidgetConfig;
public class WidgetNotifications extends AppWidgetProvider {
public static final String ACTION_SYNC_DATA = "ACTION_SYNC_DATA";
private static final String TAG = "WidgetNotifications";
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_SYNC_DATA.equals(intent.getAction())){
EdziennikTask.Companion.sync().enqueue(context);
}
super.onReceive(context, intent);
}
public static PendingIntent getPendingSelfIntent(Context context, String action) {
Intent intent = new Intent(context, WidgetNotifications.class);
intent.setAction(action);
return getPendingSelfIntent(context, intent);
}
public static PendingIntent getPendingSelfIntent(Context context, Intent intent) {
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
ComponentName thisWidget = new ComponentName(context, WidgetNotifications.class);
App app = (App)context.getApplicationContext();
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
// There may be multiple widgets active, so update all of them
for (int appWidgetId : allWidgetIds) {
WidgetConfig widgetConfig = app.appConfig.widgetTimetableConfigs.get(appWidgetId);
if (widgetConfig == null) {
widgetConfig = new WidgetConfig(-1);
app.appConfig.widgetTimetableConfigs.put(appWidgetId, widgetConfig);
app.appConfig.savePending = true;
}
RemoteViews views;
if (widgetConfig.bigStyle) {
views = new RemoteViews(context.getPackageName(), widgetConfig.darkTheme ? R.layout.widget_notifications_dark_big : R.layout.widget_notifications_big);
}
else {
views = new RemoteViews(context.getPackageName(), widgetConfig.darkTheme ? R.layout.widget_notifications_dark : R.layout.widget_notifications);
}
PorterDuff.Mode mode = PorterDuff.Mode.DST_IN;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
// this code seems to crash the launcher on >= P
float transparency = widgetConfig.opacity; //0...1
long colorFilter = 0x01000000L * (long) (255f * transparency);
try {
final Method[] declaredMethods = Class.forName("android.widget.RemoteViews").getDeclaredMethods();
final int len = declaredMethods.length;
if (len > 0) {
for (int m = 0; m < len; m++) {
final Method method = declaredMethods[m];
if (method.getName().equals("setDrawableParameters")) {
method.setAccessible(true);
method.invoke(views, R.id.widgetNotificationsListView, true, -1, (int) colorFilter, mode, -1);
method.invoke(views, R.id.widgetNotificationsHeader, true, -1, (int) colorFilter, mode, -1);
break;
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
Intent refreshIntent = new Intent(context, WidgetNotifications.class);
refreshIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingRefreshIntent = PendingIntent.getBroadcast(context,
0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widgetNotificationsRefresh, pendingRefreshIntent);
views.setOnClickPendingIntent(R.id.widgetNotificationsSync, getPendingSelfIntent(context, ACTION_SYNC_DATA));
views.setImageViewBitmap(R.id.widgetNotificationsRefresh, new IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh)
.color(IconicsColor.colorInt(Color.WHITE))
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
views.setImageViewBitmap(R.id.widgetNotificationsSync, new IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
.color(IconicsColor.colorInt(Color.WHITE))
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
//d(TAG, "Profiles: "+ Arrays.toString(profileList.toArray()));
if (app.appConfig.notifications.size() == 0) {
views.setViewVisibility(R.id.widgetNotificationsLoading, View.VISIBLE);
views.setRemoteAdapter(R.id.widgetNotificationsListView, new Intent());
views.setTextViewText(R.id.widgetNotificationsLoading, app.getString(R.string.widget_notifications_no_data));
}
else {
views.setViewVisibility(R.id.widgetNotificationsLoading, View.GONE);
Intent listIntent = new Intent(context, WidgetNotificationsService.class);
listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
listIntent.putExtra("bigStyle", widgetConfig.bigStyle);
listIntent.putExtra("darkTheme", widgetConfig.darkTheme);
listIntent.setData(Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME)));
views.setRemoteAdapter(R.id.widgetNotificationsListView, listIntent);
// template to handle the click listener for each item
Intent intentTemplate = new Intent(context, MainActivity.class);
intentTemplate.setAction("android.intent.action.MAIN");
PendingIntent pendingIntentNotifications = PendingIntent.getActivity(context, 0, intentTemplate, 0);
views.setPendingIntentTemplate(R.id.widgetNotificationsListView, pendingIntentNotifications);
}
Intent openIntent = new Intent(context, MainActivity.class);
openIntent.setAction("android.intent.action.MAIN");
openIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_NOTIFICATIONS);
PendingIntent pendingOpenIntent = PendingIntent.getActivity(context,
appWidgetId, openIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widgetNotificationsHeader, pendingOpenIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetNotificationsListView);
}
//modeInt++;
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
App app = (App) context.getApplicationContext();
for (int appWidgetId: appWidgetIds) {
app.appConfig.widgetTimetableConfigs.remove(appWidgetId);
}
app.saveConfig("widgetTimetableConfigs");
}
}

View File

@ -1,98 +0,0 @@
package pl.szczodrzynski.edziennik.widgets.notifications;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.utils.models.Date;
import pl.szczodrzynski.edziennik.utils.models.Notification;
public class WidgetNotificationsListProvider implements RemoteViewsService.RemoteViewsFactory {
private static final String TAG = "WidgetNotificationsProv";
private App app;
private Context context;
private int appWidgetId;
private boolean bigStyle;
private boolean darkTheme;
//For obtaining the activity's context and intent
public WidgetNotificationsListProvider(Context context, Intent intent) {
this.app = (App) context.getApplicationContext();
this.context = context;
this.appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0);
this.bigStyle = intent.getBooleanExtra("bigStyle", false);
this.darkTheme = intent.getBooleanExtra("darkTheme", false);
// executed only ONCE
Log.d(TAG, "appWidgetId: "+appWidgetId);
}
@Override
public void onCreate() {
}
@Override
public void onDataSetChanged() {
// executed EVERY TIME
Log.d(TAG, "onDataSetChanged for appWidgetId: "+appWidgetId);
}
@Override
public void onDestroy() {
}
@Override
public int getCount() {
return (app.appConfig.notifications == null ? 0 : app.appConfig.notifications.size());
}
@Override
public RemoteViews getViewAt(int i) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.row_widget_notifications_item);
if (i > app.appConfig.notifications.size()-1)
return views;
Notification notification = app.appConfig.notifications.get(i);
if (bigStyle) {
views = new RemoteViews(context.getPackageName(), darkTheme ? R.layout.row_widget_notifications_dark_big_item : R.layout.row_widget_notifications_big_item);
}
else if (darkTheme) {
views = new RemoteViews(context.getPackageName(), R.layout.row_widget_notifications_dark_item);
}
Intent intent = new Intent();
notification.fillIntent(intent);
views.setOnClickFillInIntent(R.id.widgetNotificationsRoot, intent);
views.setTextViewText(R.id.widgetNotificationsTitle, app.getString(R.string.widget_notifications_title_format, notification.title, Notification.stringType(context, notification.type)));
views.setTextViewText(R.id.widgetNotificationsText, notification.text);
views.setTextViewText(R.id.widgetNotificationsDate, Date.fromMillis(notification.addedDate).getFormattedString());
return views;
}
@Override
public RemoteViews getLoadingView() {
return null;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public boolean hasStableIds() {
return true;
}
}

View File

@ -1,11 +0,0 @@
package pl.szczodrzynski.edziennik.widgets.notifications;
import android.content.Intent;
import android.widget.RemoteViewsService;
public class WidgetNotificationsService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return (new WidgetNotificationsListProvider(this.getApplicationContext(), intent));
}
}

View File

@ -1,17 +0,0 @@
package pl.szczodrzynski.edziennik.widgets.timetable;
import android.content.Intent;
import android.widget.RemoteViewsService;
public class WidgetTimetableService extends RemoteViewsService {
/*
* So pretty simple just defining the Adapter of the listview
* here Adapter is ListProvider
* */
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return (new WidgetTimetableListProvider(this.getApplicationContext(), intent));
}
}

View File

@ -1,6 +1,4 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout 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:id="@+id/root" android:id="@+id/root"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -36,14 +34,6 @@
</LinearLayout> </LinearLayout>
<ImageButton
android:id="@+id/widgetNotificationsRefresh"
android:layout_width="45.0dip"
android:layout_height="45.0dip"
android:layout_gravity="end|center"
android:background="?android:selectableItemBackground"
android:contentDescription="@string/widget_refresh" />
<ImageButton <ImageButton
android:id="@+id/widgetNotificationsSync" android:id="@+id/widgetNotificationsSync"
android:layout_width="45.0dip" android:layout_width="45.0dip"

View File

@ -1,6 +1,4 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout 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:id="@+id/root" android:id="@+id/root"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -36,14 +34,6 @@
</LinearLayout> </LinearLayout>
<ImageButton
android:id="@+id/widgetNotificationsRefresh"
android:layout_width="60dip"
android:layout_height="60dip"
android:layout_gravity="end|center"
android:background="?android:selectableItemBackground"
android:contentDescription="@string/widget_refresh" />
<ImageButton <ImageButton
android:id="@+id/widgetNotificationsSync" android:id="@+id/widgetNotificationsSync"
android:layout_width="60dip" android:layout_width="60dip"

View File

@ -1,6 +1,4 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout 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:id="@+id/root" android:id="@+id/root"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -36,14 +34,6 @@
</LinearLayout> </LinearLayout>
<ImageButton
android:id="@+id/widgetNotificationsRefresh"
android:layout_width="45.0dip"
android:layout_height="45.0dip"
android:layout_gravity="end|center"
android:background="?android:selectableItemBackground"
android:contentDescription="@string/widget_refresh" />
<ImageButton <ImageButton
android:id="@+id/widgetNotificationsSync" android:id="@+id/widgetNotificationsSync"
android:layout_width="45.0dip" android:layout_width="45.0dip"

View File

@ -1,6 +1,4 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout 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:id="@+id/root" android:id="@+id/root"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -36,14 +34,6 @@
</LinearLayout> </LinearLayout>
<ImageButton
android:id="@+id/widgetNotificationsRefresh"
android:layout_width="60dip"
android:layout_height="60dip"
android:layout_gravity="end|center"
android:background="?android:selectableItemBackground"
android:contentDescription="@string/widget_refresh" />
<ImageButton <ImageButton
android:id="@+id/widgetNotificationsSync" android:id="@+id/widgetNotificationsSync"
android:layout_width="60dip" android:layout_width="60dip"

View File

@ -11,5 +11,5 @@
android:resizeMode="horizontal|vertical" android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="pl.szczodrzynski.edziennik.widgets.WidgetConfigActivity" android:configure="pl.szczodrzynski.edziennik.ui.widgets.WidgetConfigActivity"
tools:ignore="UnusedAttribute" /> tools:ignore="UnusedAttribute" />

View File

@ -11,5 +11,5 @@
android:resizeMode="horizontal|vertical" android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="5400000" android:updatePeriodMillis="5400000"
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="pl.szczodrzynski.edziennik.widgets.WidgetConfigActivity" android:configure="pl.szczodrzynski.edziennik.ui.widgets.WidgetConfigActivity"
tools:ignore="UnusedAttribute" /> tools:ignore="UnusedAttribute" />

View File

@ -11,5 +11,5 @@
android:resizeMode="horizontal|vertical" android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="1800000" android:updatePeriodMillis="1800000"
android:widgetCategory="home_screen" android:widgetCategory="home_screen"
android:configure="pl.szczodrzynski.edziennik.widgets.WidgetConfigActivity" android:configure="pl.szczodrzynski.edziennik.ui.widgets.WidgetConfigActivity"
tools:ignore="UnusedAttribute" /> tools:ignore="UnusedAttribute" />