Commit 411658f6 authored by Filip Wiesner's avatar Filip Wiesner

KosPage generic (not buildable)

parent 86fdf4aa
......@@ -38,20 +38,20 @@ kapt {
dependencies {
implementation fileTree(include: ["*.jar"], dir: "libs")
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
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.appcompat:appcompat:1.1.0-alpha02'
implementation 'com.google.android.material:material:1.1.0-alpha03'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0-alpha02'
implementation "androidx.legacy:legacy-support-v4:1.0.0"
testImplementation "junit:junit:4.12"
testImplementation 'junit:junit:4.13-beta-2'
// Testing
androidTestImplementation "androidx.test:runner:1.1.1"
androidTestImplementation "androidx.test.espresso:espresso-core:3.1.1"
androidTestImplementation 'androidx.test:runner:1.1.2-alpha01'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.2-alpha01'
//Tools
implementation "org.jetbrains.anko:anko-commons:0.10.5"
implementation "androidx.core:core-ktx:1.0.1"
implementation 'androidx.core:core-ktx:1.1.0-alpha04'
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"
......@@ -64,20 +64,20 @@ dependencies {
implementation "org.kodein.di:kodein-di-generic-jvm:6.1.0"
// 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.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.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"
// Parsing
implementation "com.google.code.gson:gson:2.8.4"
implementation 'net.danlew:android.joda:2.10.1.1'
implementation 'com.google.code.gson:gson:2.8.5'
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"
......@@ -90,12 +90,12 @@ dependencies {
kapt "androidx.room:room-compiler:2.1.0-alpha04"
// 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-core:0.9.27'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-attr:0.9.27'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-shared-preferences:0.9.27'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-build-config:0.9.27'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-crash:0.9.27'
debugImplementation 'com.willowtreeapps.hyperion:hyperion-measurement:0.9.27'
}
kotlin {
experimental {
......
......@@ -34,11 +34,11 @@
</activity>
<service
android:name="com.cvut.blackbird.flows.widget.NextEventService"
android:name="com.cvut.blackbird.widget.NextEventService"
android:exported="true"
android:enabled="true"/>
<receiver android:name="com.cvut.blackbird.flows.widget.NextEventWidget">
<receiver android:name="com.cvut.blackbird.widget.NextEventWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
......
......@@ -12,10 +12,7 @@ import com.cvut.blackbird.model.services.KosService
import com.cvut.blackbird.model.services.SiriusService
import com.cvut.blackbird.model.services.auth.InitToken
import com.cvut.blackbird.model.services.auth.RefreshTokenGuarded
import com.cvut.blackbird.model.services.kos.LoadCourses
import com.cvut.blackbird.model.services.kos.LoadTeachers
import com.cvut.blackbird.model.services.kos.LoadUser
import com.cvut.blackbird.model.services.kos.LoadEvents
import com.cvut.blackbird.model.services.kos.*
import com.cvut.blackbird.model.services.local.WipeData
import com.cvut.blackbird.model.services.other.FetchNews
import com.google.gson.GsonBuilder
......@@ -101,6 +98,7 @@ private fun Kodein.MainBuilder.setupMicroServices() {
bind<LoadCourses>() with singleton { LoadCourses(instance(), instance(), instance()) }
bind<LoadTeachers>() with singleton { LoadTeachers(instance(), instance(), instance(), instance()) }
bind<LoadUser>() with singleton { LoadUser(instance(), instance()) }
bind<LoadRooms>() with singleton { LoadRooms(instance(), instance()) }
//Local
bind<WipeData>() with singleton { WipeData(instance(), instance(), instance()) }
......
......@@ -6,9 +6,9 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.MutableLiveData
import com.cvut.blackbird.model.Loading
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Loading
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.support.glue.Glue
import com.cvut.blackbird.support.glue.SuperGlue
import kotlinx.coroutines.GlobalScope
......
......@@ -14,8 +14,7 @@ import kotlin.coroutines.CoroutineContext
abstract class BlackBirdVM: ViewModel(), CoroutineScope, KodeinAware {
override val kodein = BlackBirdAC.kodein
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO
override val coroutineContext = newSingleThreadContext("View Model")
private val jobs = hashMapOf<String, Job>()
......
package com.cvut.blackbird.flows
import androidx.lifecycle.ViewModel
class NavigationViewModel: ViewModel()
\ No newline at end of file
......@@ -12,8 +12,8 @@ import androidx.navigation.findNavController
import com.cvut.blackbird.R
import com.cvut.blackbird.extensions.appendParameters
import com.cvut.blackbird.extensions.buildUri
import com.cvut.blackbird.model.Failure
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Failure
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.model.services.AuthService
import com.cvut.blackbird.model.services.UserInfo
import com.cvut.blackbird.model.support.AuthResult
......
......@@ -6,10 +6,10 @@ import com.cvut.blackbird.extensions.asProgressTo
import com.cvut.blackbird.extensions.passTo
import com.cvut.blackbird.extensions.withDefault
import com.cvut.blackbird.flows.BlackBirdVM
import com.cvut.blackbird.model.Failure
import com.cvut.blackbird.model.NotYet
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Failure
import com.cvut.blackbird.model.support.NotYet
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.model.services.auth.InitToken
import com.cvut.blackbird.model.services.auth.RefreshTokenGuarded
import com.cvut.blackbird.model.services.kos.LoadCourses
......
......@@ -38,9 +38,6 @@ class EventDetailFragment : Fragment() {
}
private fun setupEvent(detEvent: DetailedEvent) {
if (viewModel.eventInitialized && detEvent.event == Event.empty)
findNavController().navigateUp()
this.detailedEvent = detEvent
detail_abbr.background = when(detEvent.event.eventType) {
......@@ -99,6 +96,11 @@ class EventDetailFragment : Fragment() {
}
override fun onResume() {
super.onResume()
// if (viewModel.eventInitialized && viewModel.detailedEvent.value?.event == Event.empty)
// findNavController().navigateUp()
}
override fun onPause() {
super.onPause()
......
......@@ -35,8 +35,7 @@ class EventDetailViewModel: BlackBirdVM() {
_detailedEvent.postValue(eventDao.getDetailedEvent(event.id).apply {
initTeachers(teacherDao)
})
}.invokeOnCompletion {
if (it == null) eventInitialized = true
eventInitialized = true
}
}
......
......@@ -6,6 +6,7 @@ import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.cvut.blackbird.BlackBirdAC
import com.cvut.blackbird.R
import com.cvut.blackbird.extensions.toNotifyOnSuccess
......@@ -13,6 +14,7 @@ import com.cvut.blackbird.flows.findMainNav
import com.cvut.blackbird.model.services.UserInfo
import com.cvut.blackbird.support.glue.bind
import com.cvut.blackbird.support.glue.clickTo
import com.cvut.blackbird.support.glue.observe
import kotlinx.android.synthetic.main.profile_fragment.*
class ProfileFragment : Fragment() {
......@@ -38,6 +40,10 @@ class ProfileFragment : Fragment() {
private fun setupBinding() {
this bind logOutBtn clickTo viewModel::logOut
this bind viewModel.logoutStatus toNotifyOnSuccess ::loggedOut
// observe(viewModel.rooms) {
// BlackBirdAC.log(it.toString())
// }
}
private fun loggedOut() { findMainNav()?.navigate(R.id.toAuth) }
......
......@@ -7,20 +7,35 @@ import com.cvut.blackbird.extensions.asProgressStatus
import com.cvut.blackbird.extensions.doWith
import com.cvut.blackbird.extensions.withDefault
import com.cvut.blackbird.flows.BlackBirdVM
import com.cvut.blackbird.model.NotYet
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.services.KosParameters
import com.cvut.blackbird.model.services.KosService
import com.cvut.blackbird.model.services.kos.LoadRooms
import com.cvut.blackbird.model.support.NotYet
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.model.services.local.WipeData
import com.cvut.blackbird.model.support.map
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.kodein.di.generic.instance
class ProfileViewModel : BlackBirdVM() {
private val loadRooms by instance<LoadRooms>()
private val wipeData by instance<WipeData>()
private val _logoutStatus = MutableLiveData<Result<Unit>>() withDefault NotYet()
// private val _rooms = MutableLiveData<Result<List<Room>>>() withDefault NotYet()
val logoutStatus: LiveData<Result<Unit>> get() = _logoutStatus
// val rooms: LiveData<Result<List<Room>>> get() = _rooms
init {
launch {
// _rooms.postValue(loadRooms().map {
// it.entries.map { it.rawContent as Room }
// })
}
}
var logoutJob: Job? = null
fun logOut() {
......
......@@ -11,18 +11,19 @@ import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.*
import com.cvut.blackbird.BlackBirdAC
import com.cvut.blackbird.BlackBirdAC.Companion.log
import com.cvut.blackbird.R
import com.cvut.blackbird.flows.detail.EventDetailViewModel
import com.cvut.blackbird.flows.findMainNav
import com.cvut.blackbird.model.Failure
import com.cvut.blackbird.flows.timetable.TimetableViewModel
import com.cvut.blackbird.model.support.Failure
import com.cvut.blackbird.model.entities.Event
import com.cvut.blackbird.model.entities.News
import com.cvut.blackbird.support.glue.bind
import com.cvut.blackbird.support.glue.observe
import com.cvut.blackbird.support.glue.toPassValueTo
import kotlinx.android.synthetic.main.tasks_fragment.*
import kotlinx.coroutines.launch
class TasksFragment : Fragment() {
private lateinit var viewModel: TasksViewModel
......@@ -37,10 +38,14 @@ class TasksFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(activity!!).get(TasksViewModel::class.java)
eventViewModel = ViewModelProviders.of(activity!!).get(EventDetailViewModel::class.java)
setupUi()
setupBinding()
eventViewModel = ViewModelProviders.of(activity!!).get(EventDetailViewModel::class.java)
// Preload timetable data
ViewModelProviders.of(activity!!).get(TimetableViewModel::class.java)
}
private fun setupUi() {
......
......@@ -5,10 +5,10 @@ import androidx.lifecycle.MutableLiveData
import com.chibatching.kotpref.livedata.asLiveData
import com.cvut.blackbird.extensions.*
import com.cvut.blackbird.flows.BlackBirdVM
import com.cvut.blackbird.model.Failure
import com.cvut.blackbird.model.NotYet
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Failure
import com.cvut.blackbird.model.support.NotYet
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.model.database.EventDao
import com.cvut.blackbird.model.entities.DetailedEvent
import com.cvut.blackbird.model.entities.Event
......@@ -35,7 +35,7 @@ class TasksViewModel : BlackBirdVM() {
private val _refreshResult = MutableLiveData<Result<Unit>>() withDefault NotYet()
private val _tasks = MutableLiveData<List<Task>>() withDefault listOf()
private val _news = MutableLiveData<List<News>>() withDefault listOf()
private val pinnedEvents =
EventsMeta.asLiveData(EventsMeta::pinned)
.switchMap { runBlocking(coroutineContext) {
......
......@@ -7,8 +7,8 @@ import com.cvut.blackbird.extensions.atEndOfTheDay
import com.cvut.blackbird.extensions.atStartOfTheDay
import com.cvut.blackbird.extensions.withDefault
import com.cvut.blackbird.flows.BlackBirdVM
import com.cvut.blackbird.model.NotYet
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.support.NotYet
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.database.EventDao
import com.cvut.blackbird.model.entities.Event
import com.cvut.blackbird.model.services.kos.LoadEvents
......
package com.cvut.blackbird.model
import com.tickaroo.tikxml.annotation.Element
import com.tickaroo.tikxml.annotation.Path
import com.tickaroo.tikxml.annotation.PropertyElement
import com.tickaroo.tikxml.annotation.Xml
@Xml
abstract class KosPage<T: Any> {
@PropertyElement(name = "atom:id")
val path: String = ""
@PropertyElement(name = "atom:updated")
val updated: String = ""
@Element(name = "atom:entry")
val entries: List<T> = listOf()
}
@Xml
abstract class KosEntry<T: Any> {
@PropertyElement(name = "atom:id")
var id: String = ""
@PropertyElement(name = "atom:updated")
var path: String = ""
@Path("atom:author")
@PropertyElement(name = "atom:name")
var author: String = ""
@Element
lateinit var content: T
}
\ No newline at end of file
......@@ -3,9 +3,10 @@ package com.cvut.blackbird.model.entities
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.cvut.blackbird.model.KosPage
import com.tickaroo.tikxml.annotation.*
@Xml
@Xml(inheritance = true)
class EnrolledCourseRoot (
@Element(name = "atom:entry")
val courses: List<EnrolledCourse>
......
package com.cvut.blackbird.model.services
import com.cvut.blackbird.BlackBirdAC
import com.cvut.blackbird.model.Failure
import com.cvut.blackbird.model.NotYet
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Failure
import com.cvut.blackbird.model.support.NotYet
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.support.Success
import retrofit2.Call
import java.net.HttpURLConnection
abstract class BBMicroService {
protected abstract val authService: AuthService
suspend fun refreshToken(): com.cvut.blackbird.model.Result<Unit> {
suspend fun refreshToken(): Result<Unit> {
BlackBirdAC.log("Refreshing token")
return try {
val response = authService.refreshToken().execute()
......@@ -20,15 +20,16 @@ abstract class BBMicroService {
BlackBirdAC.log("Token refreshed")
Success(Unit)
} else {
Failure(response.errorBody()?.string() ?: "No error message")
Failure(response.errorBody()?.string()
?: "No error message")
}
} catch (e: Throwable) {
Failure(e.localizedMessage)
}
}
suspend inline fun <T> fetch(call: () -> Call<T>): com.cvut.blackbird.model.Result<T> {
var result: com.cvut.blackbird.model.Result<T> = NotYet()
suspend inline fun <T> fetch(call: () -> Call<T>): Result<T> {
var result: Result<T> = NotYet()
try {
while (result is NotYet) { // repeat until we have result
......@@ -43,7 +44,8 @@ abstract class BBMicroService {
// repeat request
NotYet()
else
Failure(response.errorBody()?.string() ?: "No error message")
Failure(response.errorBody()?.string()
?: "No error message")
}
}
} catch (e: Throwable) {
......
package com.cvut.blackbird.model.services
import com.cvut.blackbird.model.entities.Course
import com.cvut.blackbird.model.entities.EnrolledCourseRoot
import com.cvut.blackbird.model.entities.Student
import com.cvut.blackbird.model.entities.Teacher
import com.cvut.blackbird.model.KosEntry
import com.cvut.blackbird.model.KosPage
import com.cvut.blackbird.model.entities.*
import retrofit2.Call
import retrofit2.http.*
class KosParameters(
val semester: String = "curr",
val offset: Int = 0,
val limit: Int = 1000,
val lang: String = "en",
val multilang: Boolean = false
)
interface KosService {
companion object {
const val url = "https://kosapi.feld.cvut.cz/api/3/"
......@@ -61,5 +68,22 @@ interface KosService {
@Query("lang") lang: String = "en",
@Query("multilang") multilang: Boolean = false
): Call<Teacher>
/**
* Room
*/
@GET("rooms/{code}")
fun getRooms(
@Path("code") roomCode: String,
@Header("Authorization") token: String = AuthInfo.accessTokenHeader,
@Query("offset") resultOffset: Int = 0,
@Query("limit") resultsLimit: Int = 1000,
@Query("lang") lang: String = "en",
@Query("multilang") multilang: Boolean = false
): Call<KosPage<KosEntry<Any>>>
}
package com.cvut.blackbird.model.services.auth
import com.cvut.blackbird.model.Failure
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Failure
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.model.services.AuthInfo
import com.cvut.blackbird.model.services.AuthService
import com.cvut.blackbird.model.services.BBMicroService
......
package com.cvut.blackbird.model.services.kos
import com.cvut.blackbird.model.Failure
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Failure
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.model.database.CourseDao
import com.cvut.blackbird.model.entities.Course
import com.cvut.blackbird.model.services.AuthService
......
package com.cvut.blackbird.model.services.kos
import com.cvut.blackbird.model.Failure
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Failure
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.model.database.EventDao
import com.cvut.blackbird.model.database.insertAll
import com.cvut.blackbird.model.services.*
......@@ -12,7 +12,7 @@ class LoadEvents(
private val siriusService: SiriusService,
private val eventDao: EventDao
) : BBMicroService() {
suspend operator fun invoke(): Result<Unit> {
suspend operator fun invoke(all: Boolean = false): Result<Unit> {
val result = fetch { siriusService.getEvents(UserInfo.username) }
if (result is Success) {
......
package com.cvut.blackbird.model.services.kos
import com.cvut.blackbird.model.KosEntry
import com.cvut.blackbird.model.KosPage
import com.cvut.blackbird.model.services.AuthService
import com.cvut.blackbird.model.services.BBMicroService
import com.cvut.blackbird.model.services.KosService
import com.cvut.blackbird.model.support.Result
class LoadRooms(
override val authService: AuthService,
private val kosService: KosService
) : BBMicroService() {
suspend operator fun invoke(): Result<KosPage<KosEntry<Any>>> = fetch { kosService.getRooms("") }
}
\ No newline at end of file
package com.cvut.blackbird.model.services.kos
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.model.database.EventDao
import com.cvut.blackbird.model.database.TeacherDao
import com.cvut.blackbird.model.database.getTeachers
......
package com.cvut.blackbird.model.services.kos
import com.cvut.blackbird.model.Failure
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.model.support.Failure
import com.cvut.blackbird.model.support.Result
import com.cvut.blackbird.model.support.Success
import com.cvut.blackbird.model.services.AuthService
import com.cvut.blackbird.model.services.BBMicroService
import com.cvut.blackbird.model.services.KosService
......@@ -20,11 +20,13 @@ class LoadUser(
UserInfo.facultyAbbr = userInfo.value.email