Commit 0c32610d authored by Filip Wiesner's avatar Filip Wiesner

Widget WIP

parent a1d3b8f2
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
......
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="navEditor-manualLayoutAlgorithm2">
<option name="myPositions">
<map>
<entry key="nav_graph.xml">
<value>
<LayoutPositions>
<option name="myPositions">
<map>
<entry key="authFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="12" />
<option name="y" value="12" />
</Point>
</option>
<option name="myPositions">
<map>
<entry key="onLogged">
<value>
<LayoutPositions />
</value>
</entry>
</map>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="navigationFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="256" />
<option name="y" value="12" />
</Point>
</option>
<option name="myPositions">
<map>
<entry key="toEventDetail">
<value>
<LayoutPositions />
</value>
</entry>
</map>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="timetableDetailFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="500" />
<option name="y" value="12" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="toAuth">
<value>
<LayoutPositions />
</value>
</entry>
</map>
</option>
</LayoutPositions>
</value>
</entry>
</map>
</option>
</component>
</project>
\ No newline at end of file
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'androidx.navigation.safeargs'
apply plugin: "com.android.application"
apply plugin: "kotlin-android"
apply plugin: "kotlin-android-extensions"
apply plugin: "kotlin-kapt"
apply plugin: "androidx.navigation.safeargs"
android {
compileSdkVersion 28
......@@ -17,10 +17,10 @@ android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
buildToolsVersion '28.0.3'
buildToolsVersion "28.0.3"
}
kapt {
......@@ -33,29 +33,29 @@ kapt {
dependencies {
def anko_version = "0.10.5"
def room_version = "2.1.0-alpha01"
def room_version = "2.1.0-alpha03"
def dagger_version = "2.16"
def nav_version = "1.0.0-alpha07"
def nav_version = "1.0.0-alpha09"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation fileTree(include: ["*.jar"], dir: "libs")
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
implementation "androidx.appcompat:appcompat:1.0.2"
implementation "com.google.android.material:material:1.0.0"
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
implementation "androidx.legacy:legacy-support-v4:1.0.0"
testImplementation "junit:junit:4.12"
// Testing
androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
androidTestImplementation "androidx.test:runner:1.1.1"
androidTestImplementation "androidx.test.espresso:espresso-core:3.1.1"
//Tools
implementation "org.jetbrains.anko:anko-commons:$anko_version"
implementation 'androidx.core:core-ktx:1.0.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.27.0-eap13'
implementation "androidx.core:core-ktx:1.0.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.27.0-eap13"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation 'com.github.magneticflux:kotlin-livedata-utils:0.3.3'
implementation "com.github.magneticflux:kotlin-livedata-utils:0.3.3"
//Navigation
implementation "android.arch.navigation:navigation-fragment-ktx:$nav_version"
......@@ -68,39 +68,39 @@ dependencies {
kapt "com.google.dagger:dagger-android-processor:$dagger_version"
// Networking
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.tickaroo.tikxml:retrofit-converter:0.8.13'
implementation "com.squareup.retrofit2:retrofit:2.4.0"
implementation "com.squareup.retrofit2:converter-gson:2.4.0"
implementation "com.tickaroo.tikxml:retrofit-converter:0.8.13"
// Shared Prefs
implementation 'com.chibatching.kotpref:kotpref:2.6.0'
implementation 'com.chibatching.kotpref:livedata-support:2.6.0'
implementation "com.chibatching.kotpref:kotpref:2.6.0"
implementation "com.chibatching.kotpref:livedata-support:2.6.0"
// Parsing
implementation 'com.google.code.gson:gson:2.8.4'
implementation 'com.tickaroo.tikxml:annotation:0.8.13'
implementation 'com.tickaroo.tikxml:core:0.8.13'
kapt 'com.tickaroo.tikxml:processor:0.8.13'
implementation 'net.danlew:android.joda:2.9.9.4'
implementation "com.google.code.gson:gson:2.8.4"
implementation "com.tickaroo.tikxml:annotation:0.8.13"
implementation "com.tickaroo.tikxml:core:0.8.13"
kapt "com.tickaroo.tikxml:processor:0.8.13"
implementation "net.danlew:android.joda:2.9.9.4"
// Animation/Trasnition
implementation 'bg.devlabs.transitioner:transitioner:1.3'
implementation 'com.github.florent37:kotlinpleaseanimate:1.0.4'
implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'
implementation "bg.devlabs.transitioner:transitioner:1.3"
implementation "com.github.florent37:kotlinpleaseanimate:1.0.4"
implementation "androidx.dynamicanimation:dynamicanimation:1.0.0"
// Database
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.paging:paging-runtime:$room_version"
implementation "androidx.paging:paging-runtime:2.1.0-rc01"
kapt "androidx.room:room-compiler:$room_version"
// Debug
debugImplementation 'com.willowtreeapps.hyperion:hyperion-core:0.9.23'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-attr:0.9.23'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-shared-preferences:0.9.23'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-build-config:0.9.24'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-crash:0.9.24'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-measurement:0.9.24'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-geiger-counter:0.9.24'
debugImplementation "com.willowtreeapps.hyperion:hyperion-core:0.9.23"
debugImplementation "com.willowtreeapps.hyperion:hyperion-attr:0.9.23"
debugImplementation "com.willowtreeapps.hyperion:hyperion-shared-preferences:0.9.23"
debugImplementation "com.willowtreeapps.hyperion:hyperion-build-config:0.9.24"
debugImplementation "com.willowtreeapps.hyperion:hyperion-crash:0.9.24"
debugImplementation "com.willowtreeapps.hyperion:hyperion-measurement:0.9.24"
debugImplementation "com.willowtreeapps.hyperion:hyperion-geiger-counter:0.9.24"
}
kotlin {
experimental {
......
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cvut.blackbird">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<application
android:name=".BlackBirdAC"
android:allowBackup="true"
android:icon="@drawable/ic_raven"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".flows.BlackBirdMain">
<nav-graph android:value="@navigation/nav_graph"/>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="callback"
android:scheme="kosapp"/>
</intent-filter>
</activity>
</application>
</manifest>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cvut.blackbird">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name=".BlackBirdAC"
android:allowBackup="true"
android:icon="@drawable/ic_raven"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".flows.BlackBirdMain">
<nav-graph android:value="@navigation/nav_graph" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="callback"
android:scheme="kosapp" />
</intent-filter>
</activity>
<receiver android:name="com.cvut.blackbird.flows.widget.NextEventWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/next_event_widget_info" />
</receiver>
</application>
</manifest>
package com.cvut.blackbird
import android.app.Application
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.util.Log
import androidx.fragment.app.FragmentManager
import com.chibatching.kotpref.Kotpref
......@@ -9,6 +11,9 @@ import com.cvut.blackbird.dinjection.components.DaggerApplicationComponent
import com.cvut.blackbird.dinjection.modules.ServicesModule
import com.cvut.blackbird.dinjection.modules.RoomModule
import net.danlew.android.joda.JodaTimeAndroid
import androidx.core.view.accessibility.AccessibilityEventCompat.setAction
import android.content.Intent
import com.cvut.blackbird.flows.widget.NextEventWidget
class BlackBirdAC: Application(){
......@@ -30,5 +35,11 @@ class BlackBirdAC: Application(){
JodaTimeAndroid.init(this)
Kotpref.init(this)
val intent = Intent(this, NextEventWidget::class.java)
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
val ids = AppWidgetManager.getInstance(this).getAppWidgetIds(ComponentName(this, NextEventWidget::class.java))
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
sendBroadcast(intent)
}
}
package com.cvut.blackbird.flows.widget
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.widget.RemoteViews
import androidx.room.Room
import com.cvut.blackbird.R
import com.cvut.blackbird.extensions.courseAbbr
import com.cvut.blackbird.model.database.BlackBirdDB
import com.cvut.blackbird.model.entities.EventType
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.jetbrains.anko.toast
import org.joda.time.DateTime
import kotlin.reflect.jvm.jvmName
/**
* Implementation of App Widget functionality.
*/
class NextEventWidget : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
val db: BlackBirdDB = Room
.databaseBuilder(context, BlackBirdDB::class.java, "blackbird_DB")
.fallbackToDestructiveMigration()
.build()
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds)
updateAppWidget(context, appWidgetManager, appWidgetId, db)
}
override fun onEnabled(context: Context) {
// Enter relevant functionality for when the first widget is created
}
override fun onDisabled(context: Context) {
// Enter relevant functionality for when the last widget is disabled
}
companion object {
internal fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int,
database: BlackBirdDB
) {
// Construct the RemoteViews object
context.toast("")
val views = RemoteViews(context.packageName, R.layout.next_event_widget)
runBlocking { GlobalScope.launch {
val nextEvent = database.eventDao().nextEvent()
nextEvent?.let {
val time = (it.event.startsAt.millis - DateTime.now().millis) / 1000
views.setTextViewText(R.id.widget_timeLeft, time.millisToTimeText())
views.setTextViewText(R.id.widget_courseIcon, it.courseEnt?.code?.courseAbbr)
views.setInt(R.id.widget_courseIcon, "setBackground",
when(it.event.eventType) {
EventType.LECTURE -> R.drawable.ic_timetable_lecture
EventType.TUTORIAL -> R.drawable.ic_timetable_tutorial
else -> R.drawable.ic_timetable_info
})
}
} }
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
fun Long.millisToTimeText() = buildString {
val time = this@millisToTimeText
append("in ")
if (time < 60) append(time.toString() + " min")
else {
if (time / 60 > 0) append((time / 60).toString() + " h ")
if (time % 60 > 0) append((time % 60).toString() + " min")
else {
delete(length - 2, length)
append(" h")
}
}
}
......@@ -42,6 +42,8 @@ interface EventDao {
@Query("DELETE FROM Event")
fun deleteAllEvents()
@Query("SELECT * FROM Event WHERE startsAt > :now ORDER BY startsAt LIMIT 1")
fun nextEvent(now: Long = DateTime.now().millis): DetailedEvent?
/** DETAILED EVENT */
......
......@@ -15,6 +15,6 @@ class MeasuringViewPager : ViewPager {
val v = findViewWithTag<View>(currentItem)
v.measure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
super.onMeasure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(v.getMeasuredHeight(), View.MeasureSpec.EXACTLY))
super.onMeasure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(v.measuredHeight, View.MeasureSpec.EXACTLY))
}
}
\ No newline at end of file
......@@ -7,7 +7,7 @@ class Kolor(colorInt: Int) : Color() {
companion object {
fun fromHex(string: String) = Kolor(parseColor(string))
fun fromSeed(seed: Int): Kolor {
var shuffled = seed.toString()
val shuffled = seed.toString()
.toCharArray()
shuffled.reverse()
val color = StringBuilder(String.format("#%x", shuffled.contentHashCode()))
......@@ -17,7 +17,7 @@ class Kolor(colorInt: Int) : Color() {
}
}
private val hsvColor = HSVColor.fromColorInt(colorInt)
private val hsvColor = HSVKolor.fromColorInt(colorInt)
var saturation
get() = hsvColor.saturation
......@@ -32,27 +32,27 @@ class Kolor(colorInt: Int) : Color() {
fun withBrightness(b: Float): Kolor = apply { brightness = b }
fun withSaturation(s: Float): Kolor = apply { saturation = s }
}
data class HSVColor (var hue: Float, var saturation: Float, var brightness: Float) {
companion object {
fun fromColorInt(color: Int): HSVColor {
val hsvColor = FloatArray(3)
Color.colorToHSV(color, hsvColor)
return HSVColor(
hsvColor[0],
hsvColor[1],
hsvColor[2]
)
data class HSVKolor (var hue: Float, var saturation: Float, var brightness: Float) {
companion object {
fun fromColorInt(color: Int): HSVKolor {
val hsvColor = FloatArray(3)
Color.colorToHSV(color, hsvColor)
return HSVKolor(
hsvColor[0],
hsvColor[1],
hsvColor[2]
)
}
}
}
fun toArray() = FloatArray(3) {
when(it){
0 -> hue
1 -> saturation
2 -> brightness
else -> 0f
fun toArray() = FloatArray(3) {
when(it){
0 -> hue
1 -> saturation
2 -> brightness
else -> 0f
}
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke
android:width="1dp"
android:color="@android:color/transparent" />
<solid android:color="#ffffff" />
<padding
android:left="1dp"
android:right="1dp"
android:top="1dp" />
<corners android:radius="12dp" />
</shape>
\ No newline at end of file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/slightly_rounded"
android:backgroundTint="@color/backgroundDarkColor"
android:padding="1dp"
android:orientation="vertical"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal">
<TextView
android:id="@+id/widget_timeLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginStart="8dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:fontFamily="sans-serif-condensed"
android:lines="1"
tools:text="in 8 min"
android:textColor="@color/colorTextLight"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/widget_courseIcon"
android:layout_width="52dp"
android:layout_height="52dp"
android:background="@drawable/ic_timetable_lecture"
android:fontFamily="sans-serif-condensed"
android:gravity="center"
android:textColor="@android:color/white"
android:textSize="16sp"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
tools:text="EAR" />
</LinearLayout>
\ No newline at end of file
......@@ -17,16 +17,21 @@
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
</fragment>
<fragment
android:id="@+id/authFragment"
android:name="com.cvut.blackbird.flows.authentication.AuthFragment"
android:label="auth_fragment"
tools:layout="@layout/auth_fragment">
<deepLink app:uri="kosapp://callback" />
<action android:id="@+id/onLogged"
app:destination="@id/navigationFragment"
app:clearTask="true" />
app:launchSingleTop="true"
app:popUpTo="@+id/nav_graph"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/timetableDetailFragment"
android:name="com.cvut.blackbird.flows.detail.EventDetailFragment"
......@@ -35,8 +40,14 @@
</fragment>
<!-- ACTIONS -->
<action
android:id="@+id/toAuth"
app:destination="@id/authFragment"
app:clearTask="true"/>
app:launchSingleTop="true"