Updated dependencies
This commit is contained in:
@@ -1,17 +1,16 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'androidx.navigation.safeargs.kotlin'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.3"
|
||||
compileSdkVersion 31
|
||||
buildToolsVersion "30.0.2"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "de.sebse.fuplanner2"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
targetSdkVersion 31
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
@@ -31,6 +30,10 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
@@ -52,28 +55,26 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.2.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'com.google.android.material:material:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.2.1'
|
||||
implementation 'androidx.fragment:fragment:1.2.4'
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
||||
implementation 'com.android.volley:volley:1.1.1'
|
||||
implementation 'androidx.room:room-runtime:2.2.5'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
|
||||
kapt 'androidx.room:room-compiler:2.2.5'
|
||||
implementation 'androidx.room:room-ktx:2.2.5'
|
||||
implementation 'com.beust:klaxon:5.0.1'
|
||||
implementation 'androidx.work:work-runtime-ktx:2.3.4'
|
||||
implementation 'androidx.paging:paging-runtime:2.1.2'
|
||||
implementation 'com.github.thellmund.android-week-view:core:4.1.5'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
debugImplementation 'com.amitshekhar.android:debug-db:1.0.6'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.3.6'
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation 'com.android.volley:volley:1.2.1'
|
||||
implementation 'androidx.room:room-runtime:2.3.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
|
||||
kapt 'androidx.room:room-compiler:2.3.0'
|
||||
implementation 'androidx.room:room-ktx:2.3.0'
|
||||
implementation 'com.beust:klaxon:5.5'
|
||||
implementation 'androidx.work:work-runtime-ktx:2.7.0'
|
||||
implementation 'androidx.paging:paging-runtime-ktx:3.0.1'
|
||||
implementation 'com.github.thellmund:android-week-view:5.3.2'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
}
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/FUTheme"
|
||||
android:name=".CustomApplication">
|
||||
<activity android:name=".StartupActivity"
|
||||
android:theme="@style/FUTheme.NoActionBar">
|
||||
<activity
|
||||
android:name=".StartupActivity"
|
||||
android:theme="@style/FUTheme.NoActionBar"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -29,8 +31,10 @@
|
||||
</activity>
|
||||
<activity android:name=".auth.FuplannerAccountActivity"
|
||||
android:theme="@style/FUTheme" />
|
||||
<service android:name=".auth.FuplannerAccountService"
|
||||
android:permission="de.sebse.fuauth">
|
||||
<service
|
||||
android:name=".auth.FuplannerAccountService"
|
||||
android:permission="de.sebse.fuauth"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.accounts.AccountAuthenticator" />
|
||||
</intent-filter>
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.*
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.navigateUp
|
||||
import androidx.navigation.ui.setupActionBarWithNavController
|
||||
@@ -20,9 +21,8 @@ import de.sebse.fuplanner2.auth.AppAccounts
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.database.User
|
||||
import de.sebse.fuplanner2.utils.console
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.app_bar_main.*
|
||||
import de.sebse.fuplanner2.databinding.ActivityMainBinding
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -31,30 +31,33 @@ class MainActivity() : AppCompatActivity() {
|
||||
|
||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||
private lateinit var activityViewModel: MainActivityViewModel
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
setSupportActionBar(toolbar)
|
||||
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
|
||||
val navController = navHostFragment.navController
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setSupportActionBar(binding.appBarMain.toolbar)
|
||||
|
||||
val navController = findNavController(R.id.nav_host_fragment)
|
||||
activityViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
|
||||
|
||||
activityViewModel.user.observe(this) {
|
||||
nav_view.getHeaderView(0).run {
|
||||
binding.navView.getHeaderView(0).run {
|
||||
findViewById<TextView>(R.id.nav_header_title).text = getString(R.string.full_name, it?.firstName, it?.lastName)
|
||||
findViewById<TextView>(R.id.nav_header_subtitle).text = it?.email
|
||||
}
|
||||
}
|
||||
activityViewModel.notificationCnt.observe(this) {
|
||||
nav_view.menu.findItem(R.id.nav_notifications).apply {
|
||||
binding.navView.menu.findItem(R.id.nav_notifications).apply {
|
||||
icon = ContextCompat.getDrawable(
|
||||
this@MainActivity,
|
||||
if (it == 0) R.drawable.ic_menu_notifications_none else R.drawable.ic_menu_notifications
|
||||
)
|
||||
actionView = if (it == 0)
|
||||
null
|
||||
else layoutInflater.inflate(R.layout.nav_action_view_counter, nav_view, false).apply {
|
||||
else layoutInflater.inflate(R.layout.nav_action_view_counter, binding.navView, false).apply {
|
||||
findViewById<TextView>(R.id.counterText).text = when (it) {
|
||||
in 0..99 -> it.toString()
|
||||
else -> "99+"
|
||||
@@ -63,23 +66,23 @@ class MainActivity() : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
activityViewModel.latestSemester.observe(this) {
|
||||
val courseOrder = nav_view.menu.findItem(R.id.nav_courses).order
|
||||
var i = nav_view.menu.size() - 1
|
||||
val courseOrder = binding.navView.menu.findItem(R.id.nav_courses).order
|
||||
var i = binding.navView.menu.size() - 1
|
||||
while(i >= 0) {
|
||||
val menuItem: MenuItem = nav_view.menu.getItem(i--)
|
||||
val menuItem: MenuItem = binding.navView.menu.getItem(i--)
|
||||
if (menuItem.order / 100 == courseOrder / 100 && menuItem.order != courseOrder) {
|
||||
nav_view.menu.removeItem(menuItem.itemId)
|
||||
binding.navView.menu.removeItem(menuItem.itemId)
|
||||
}
|
||||
}
|
||||
it.mapIndexed { index, course ->
|
||||
val itemOrder = courseOrder / 100 * 100 + index + 2
|
||||
nav_view.menu.add(0, itemOrder, itemOrder, course.title).setOnMenuItemClickListener {
|
||||
binding.navView.menu.add(0, itemOrder, itemOrder, course.title).setOnMenuItemClickListener {
|
||||
navController.navigate(
|
||||
R.id.course_details,
|
||||
bundleOf("courseId" to course.uid, "title" to course.title),
|
||||
NavOptions.Builder().setPopUpTo(R.id.nav_courses, false).build()
|
||||
)
|
||||
drawer_layout.closeDrawers()
|
||||
binding.drawerLayout.closeDrawers()
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -87,10 +90,10 @@ class MainActivity() : AppCompatActivity() {
|
||||
|
||||
appBarConfiguration = AppBarConfiguration(
|
||||
setOf(R.id.nav_courses, R.id.nav_canteen, R.id.nav_schedule, R.id.nav_notifications),
|
||||
drawer_layout
|
||||
binding.drawerLayout
|
||||
)
|
||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||
nav_view.setupWithNavController(navController)
|
||||
binding.navView.setupWithNavController(navController)
|
||||
|
||||
if (intent.getBooleanExtra(EXTRA_OPEN_NOTIFICATIONS, false)) {
|
||||
navController.navigate(R.id.nav_notifications)
|
||||
@@ -138,6 +141,7 @@ class MainActivityViewModel : ViewModel() {
|
||||
val notificationCnt: LiveData<Int> = database.notificationDao().getUnreadRowCount()
|
||||
val latestSemester: LiveData<List<Course>> = database.courseDao().getLatestSemester()
|
||||
|
||||
@DelicateCoroutinesApi
|
||||
fun updateSelectedUser(account: Account) {
|
||||
GlobalScope.launch {
|
||||
user.postValue(database.userDao().findByUsername(account.name))
|
||||
|
||||
@@ -29,7 +29,7 @@ abstract class FUAuthModule {
|
||||
if (response.networkResponse.statusCode == 200) {
|
||||
return parseResponse(response.body)
|
||||
} else {
|
||||
val relLocation = response.headers["Location"]
|
||||
val relLocation = response.headers?.get("Location")
|
||||
?: throw invalidResponse(100110, "No IDP form location!")
|
||||
val formUri = URI(samlUrl).resolve(relLocation).toString()
|
||||
requester.head(formUri, getCookies(user))
|
||||
@@ -72,8 +72,8 @@ abstract class FUAuthModule {
|
||||
}
|
||||
|
||||
private fun updateCookies(user: User, response: NetData) {
|
||||
val setCookies = parseCookies(response.networkResponse.allHeaders)
|
||||
setCookies["JSESSIONID"]?.let {
|
||||
val setCookies = response.networkResponse.allHeaders?.let { parseCookies(it) }
|
||||
setCookies?.get("JSESSIONID")?.let {
|
||||
user.cookies.idpJsessionId = it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ object Blackboard: FUAuthModule() {
|
||||
override suspend fun login(ctx: Context, name: String, password: String, user: User) {
|
||||
val requester = Requester(ctx)
|
||||
var response = requester.head(LOGIN_URL, cookies = getCookies(user, shib = true))
|
||||
val samlUri = response.headers["Location"]
|
||||
val samlUri = response.headers?.get("Location")
|
||||
?: throw invalidResponse(101100, "Location header not set!")
|
||||
|
||||
if (!samlUri.startsWith(RESTORE_SESSION_URI)) {
|
||||
@@ -56,13 +56,13 @@ object Blackboard: FUAuthModule() {
|
||||
updateCookies(user, response)
|
||||
// Finish BB
|
||||
response = requester.get(
|
||||
response.networkResponse.headers["Location"] ?: throw invalidResponse(101101, "No Location header to finish Blackboard"),
|
||||
response.networkResponse.headers?.get("Location") ?: throw invalidResponse(101101, "No Location header to finish Blackboard"),
|
||||
getCookies(user, shib = true)
|
||||
)
|
||||
}
|
||||
// Start Session
|
||||
response = requester.get(
|
||||
response.networkResponse.headers["Location"] ?: throw invalidResponse(101102, "No Location header to start Blackboard session"),
|
||||
response.networkResponse.headers?.get("Location") ?: throw invalidResponse(101102, "No Location header to start Blackboard session"),
|
||||
getCookies(user, shib = true)
|
||||
)
|
||||
|
||||
@@ -88,19 +88,19 @@ object Blackboard: FUAuthModule() {
|
||||
}
|
||||
|
||||
private fun updateCookies(user: User, response: NetData) {
|
||||
val setCookies = parseCookies(response.networkResponse.allHeaders)
|
||||
setCookies["JSESSIONID"]?.let {
|
||||
val setCookies = response.networkResponse.allHeaders?.let { parseCookies(it) }
|
||||
setCookies?.get("JSESSIONID")?.let {
|
||||
user.cookies.bbJsessionId = it
|
||||
}
|
||||
setCookies["session_id"]?.let {
|
||||
setCookies?.get("session_id")?.let {
|
||||
user.cookies.bbSessionId = it
|
||||
}
|
||||
setCookies["s_session_id"]?.let {
|
||||
setCookies?.get("s_session_id")?.let {
|
||||
user.cookies.bbSSessionId = it
|
||||
}
|
||||
setCookies
|
||||
.filter{ (key, _) -> key.startsWith("_shibsession_") }
|
||||
.forEach { (key, value) ->
|
||||
?.filter{ (key, _) -> key.startsWith("_shibsession_") }
|
||||
?.forEach { (key, value) ->
|
||||
user.cookies.bbShibKey = key
|
||||
user.cookies.bbShibValue = value
|
||||
return@forEach
|
||||
|
||||
@@ -31,7 +31,7 @@ suspend fun Blackboard.getEvents(ctx: Context, database: AppDatabase, user: User
|
||||
null
|
||||
).let {
|
||||
Regex("lv/([0-9]+)\\?")
|
||||
.find(it.headers["Location"] ?: "")
|
||||
.find(it.headers?.get("Location") ?: "")
|
||||
?.groups
|
||||
?.get(1)
|
||||
?.value
|
||||
|
||||
@@ -72,7 +72,7 @@ class CustomRequest: Request<NetData> {
|
||||
}
|
||||
|
||||
override fun parseNetworkResponse(response: NetworkResponse): Response<NetData>? {
|
||||
val parsed: String = parse(response.data, response.headers) ?: ""
|
||||
val parsed: String = response.headers?.let { parse(response.data, it) } ?: ""
|
||||
return Response.success(NetData(parsed, response), HttpHeaderParser.parseCacheHeaders(response))
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,16 @@ import androidx.work.workDataOf
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.auth.AppAccounts
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.databinding.ActivityMainBinding
|
||||
import de.sebse.fuplanner2.databinding.FragmentRefreshRecyclerBinding
|
||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker.Companion.KEY_ACCOUNT_NAME
|
||||
import de.sebse.fuplanner2.worker.CourseWorker
|
||||
import kotlinx.android.synthetic.main.fragment_refresh_recycler.view.*
|
||||
|
||||
class CoursesFragment : Fragment() {
|
||||
|
||||
private lateinit var coursesViewModel: CoursesViewModel
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var binding: FragmentRefreshRecyclerBinding
|
||||
|
||||
|
||||
override fun onCreateView(
|
||||
@@ -34,13 +36,14 @@ class CoursesFragment : Fragment() {
|
||||
val viewManager = LinearLayoutManager(context)
|
||||
val viewAdapter = CoursesAdapter(this::onClick)
|
||||
coursesViewModel = ViewModelProvider(this).get(CoursesViewModel::class.java)
|
||||
binding = FragmentRefreshRecyclerBinding.inflate(inflater, container, false)
|
||||
return inflater.inflate(R.layout.fragment_refresh_recycler, container, false).apply {
|
||||
recycler_view.apply {
|
||||
binding.recyclerView.apply {
|
||||
//setHasFixedSize(true)
|
||||
layoutManager = viewManager
|
||||
adapter = viewAdapter
|
||||
}
|
||||
swipe_refresh_layout.setOnRefreshListener {
|
||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||
val work = OneTimeWorkRequestBuilder<CourseWorker>()
|
||||
.setInputData(workDataOf(
|
||||
KEY_ACCOUNT_NAME to AppAccounts.getInstance().selectedAccount?.name
|
||||
@@ -50,9 +53,9 @@ class CoursesFragment : Fragment() {
|
||||
.enqueue(work)
|
||||
WorkManager.getInstance(context.applicationContext)
|
||||
.getWorkInfoByIdLiveData(work.id)
|
||||
.observe(viewLifecycleOwner, Observer {
|
||||
.observe(viewLifecycleOwner, {
|
||||
if (it.state.isFinished)
|
||||
swipe_refresh_layout.isRefreshing = false
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
})
|
||||
}
|
||||
coursesViewModel.text.observe(viewLifecycleOwner, Observer {
|
||||
|
||||
@@ -17,12 +17,11 @@ import androidx.work.workDataOf
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.auth.AppAccounts
|
||||
import de.sebse.fuplanner2.database.Lecturer
|
||||
import de.sebse.fuplanner2.utils.console
|
||||
import de.sebse.fuplanner2.databinding.FragmentRefreshRecyclerBinding
|
||||
import de.sebse.fuplanner2.utils.enqueueOneTimeWork
|
||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker.Companion.KEY_ACCOUNT_NAME
|
||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker.Companion.KEY_COURSE_ID
|
||||
import de.sebse.fuplanner2.worker.CourseWorker
|
||||
import kotlinx.android.synthetic.main.fragment_refresh_recycler.view.*
|
||||
|
||||
|
||||
class DetailsFragment : Fragment() {
|
||||
@@ -31,6 +30,7 @@ class DetailsFragment : Fragment() {
|
||||
private val args: DetailsFragmentArgs by navArgs()
|
||||
private val detailsViewModel: DetailsViewModel by viewModels { DetailsViewModelFactory(args.courseId) }
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var binding: FragmentRefreshRecyclerBinding
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
@@ -39,13 +39,13 @@ class DetailsFragment : Fragment() {
|
||||
val viewManager = LinearLayoutManager(context)
|
||||
val viewAdapter = DetailsAdapter(this::launchFragment, this::sendMail)
|
||||
return inflater.inflate(R.layout.fragment_refresh_recycler, container, false).apply {
|
||||
recycler_view.apply {
|
||||
binding.recyclerView.apply {
|
||||
setHasFixedSize(true)
|
||||
|
||||
layoutManager = viewManager
|
||||
adapter = viewAdapter
|
||||
}
|
||||
swipe_refresh_layout.setOnRefreshListener {
|
||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||
enqueueOneTimeWork<CourseWorker>(context.applicationContext) {
|
||||
it.setInputData(workDataOf(
|
||||
KEY_ACCOUNT_NAME to AppAccounts.getInstance().selectedAccount?.name,
|
||||
@@ -53,7 +53,7 @@ class DetailsFragment : Fragment() {
|
||||
))
|
||||
}.observe(viewLifecycleOwner, Observer {
|
||||
if (it.state.isFinished)
|
||||
swipe_refresh_layout.isRefreshing = false
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
})
|
||||
}
|
||||
detailsViewModel.course.observe(viewLifecycleOwner, Observer {
|
||||
|
||||
@@ -8,7 +8,7 @@ import de.sebse.fuplanner2.database.Course
|
||||
|
||||
|
||||
class DetailsViewModelFactory(private val courseId: Long): ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T = DetailsViewModel(courseId) as T
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = DetailsViewModel(courseId) as T
|
||||
}
|
||||
|
||||
class DetailsViewModel(courseId: Long) : ViewModel() {
|
||||
|
||||
@@ -14,12 +14,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.work.workDataOf
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.auth.AppAccounts
|
||||
import de.sebse.fuplanner2.databinding.FragmentRefreshRecyclerBinding
|
||||
import de.sebse.fuplanner2.utils.console
|
||||
import de.sebse.fuplanner2.utils.enqueueOneTimeWork
|
||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker.Companion.KEY_ACCOUNT_NAME
|
||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker.Companion.KEY_COURSE_ID
|
||||
import de.sebse.fuplanner2.worker.AnnouncementWorker
|
||||
import kotlinx.android.synthetic.main.fragment_refresh_recycler.view.*
|
||||
|
||||
class AnnouncementsFragment : Fragment() {
|
||||
|
||||
@@ -27,6 +27,7 @@ class AnnouncementsFragment : Fragment() {
|
||||
private val args: AnnouncementsFragmentArgs by navArgs()
|
||||
private val announcementsViewModel: AnnouncementsViewModel by viewModels { AnnouncementsViewModelFactory(args.courseId) }
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var binding: FragmentRefreshRecyclerBinding
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
@@ -35,14 +36,14 @@ class AnnouncementsFragment : Fragment() {
|
||||
val viewManager = LinearLayoutManager(context)
|
||||
val viewAdapter = AnnouncementsAdapter()
|
||||
return inflater.inflate(R.layout.fragment_refresh_recycler, container, false).apply {
|
||||
console.log(findViewById(R.id.recycler_view), recycler_view)
|
||||
recycler_view.apply {
|
||||
console.log(findViewById(R.id.recycler_view), binding.recyclerView)
|
||||
binding.recyclerView.apply {
|
||||
setHasFixedSize(true)
|
||||
|
||||
layoutManager = viewManager
|
||||
adapter = viewAdapter
|
||||
}
|
||||
swipe_refresh_layout.setOnRefreshListener {
|
||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||
enqueueOneTimeWork<AnnouncementWorker>(context.applicationContext) {
|
||||
it.setInputData(workDataOf(
|
||||
KEY_ACCOUNT_NAME to AppAccounts.getInstance().selectedAccount?.name,
|
||||
@@ -50,7 +51,7 @@ class AnnouncementsFragment : Fragment() {
|
||||
))
|
||||
}.observe(viewLifecycleOwner, Observer {
|
||||
if (it.state.isFinished)
|
||||
swipe_refresh_layout.isRefreshing = false
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
})
|
||||
}
|
||||
announcementsViewModel.events.observe(viewLifecycleOwner, Observer {
|
||||
|
||||
@@ -9,7 +9,7 @@ import de.sebse.fuplanner2.database.Announcement
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
|
||||
class AnnouncementsViewModelFactory(private val courseId: Long): ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T = AnnouncementsViewModel(courseId) as T
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = AnnouncementsViewModel(courseId) as T
|
||||
}
|
||||
|
||||
class AnnouncementsViewModel(courseId: Long) : ViewModel() {
|
||||
|
||||
@@ -14,9 +14,9 @@ import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.databinding.FragmentDescriptionBinding
|
||||
import de.sebse.fuplanner2.ui.details.DetailsViewModel
|
||||
import de.sebse.fuplanner2.ui.details.DetailsViewModelFactory
|
||||
import kotlinx.android.synthetic.main.fragment_description.view.*
|
||||
|
||||
|
||||
class DescriptionFragment : Fragment() {
|
||||
@@ -25,6 +25,7 @@ class DescriptionFragment : Fragment() {
|
||||
private val args: DescriptionFragmentArgs by navArgs()
|
||||
private val detailsViewModel: DetailsViewModel by viewModels { DetailsViewModelFactory(args.courseId) }
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var binding: FragmentDescriptionBinding
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
@@ -33,10 +34,10 @@ class DescriptionFragment : Fragment() {
|
||||
return inflater.inflate(R.layout.fragment_description, container, false).apply {
|
||||
val nightModeFlags = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
||||
if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
description.settings.forceDark = WebSettings.FORCE_DARK_ON
|
||||
binding.description.settings.forceDark = WebSettings.FORCE_DARK_ON
|
||||
}
|
||||
detailsViewModel.course.observe(viewLifecycleOwner, Observer {
|
||||
description.loadDataWithBaseURL("", it.description, "text/html", "UTF-8", "")
|
||||
binding.description.loadDataWithBaseURL("", it.description, "text/html", "UTF-8", "")
|
||||
})
|
||||
navController = findNavController()
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.work.workDataOf
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.auth.AppAccounts
|
||||
import de.sebse.fuplanner2.databinding.FragmentRefreshRecyclerBinding
|
||||
import de.sebse.fuplanner2.utils.enqueueOneTimeWork
|
||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker.Companion.KEY_ACCOUNT_NAME
|
||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker.Companion.KEY_COURSE_ID
|
||||
import de.sebse.fuplanner2.worker.CourseWorker
|
||||
import de.sebse.fuplanner2.worker.EventWorker
|
||||
import kotlinx.android.synthetic.main.fragment_refresh_recycler.view.*
|
||||
|
||||
|
||||
class EventsFragment : Fragment() {
|
||||
@@ -28,6 +28,7 @@ class EventsFragment : Fragment() {
|
||||
private val args: EventsFragmentArgs by navArgs()
|
||||
private val eventsViewModel: EventsViewModel by viewModels { EventsViewModelFactory(args.courseId) }
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var binding: FragmentRefreshRecyclerBinding
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
@@ -36,13 +37,13 @@ class EventsFragment : Fragment() {
|
||||
val viewManager = LinearLayoutManager(context)
|
||||
val viewAdapter = EventsAdapter()
|
||||
return inflater.inflate(R.layout.fragment_refresh_recycler, container, false).apply {
|
||||
recycler_view.apply {
|
||||
binding.recyclerView.apply {
|
||||
setHasFixedSize(true)
|
||||
|
||||
layoutManager = viewManager
|
||||
adapter = viewAdapter
|
||||
}
|
||||
swipe_refresh_layout.setOnRefreshListener {
|
||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||
enqueueOneTimeWork<EventWorker>(context.applicationContext) {
|
||||
it.setInputData(workDataOf(
|
||||
KEY_ACCOUNT_NAME to AppAccounts.getInstance().selectedAccount?.name,
|
||||
@@ -50,7 +51,7 @@ class EventsFragment : Fragment() {
|
||||
))
|
||||
}.observe(viewLifecycleOwner, Observer {
|
||||
if (it.state.isFinished)
|
||||
swipe_refresh_layout.isRefreshing = false
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
})
|
||||
}
|
||||
eventsViewModel.events.observe(viewLifecycleOwner, Observer {
|
||||
|
||||
@@ -10,7 +10,7 @@ import de.sebse.fuplanner2.database.Event
|
||||
|
||||
|
||||
class EventsViewModelFactory(private val courseId: Long): ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T = EventsViewModel(courseId) as T
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = EventsViewModel(courseId) as T
|
||||
}
|
||||
|
||||
class EventsViewModel(courseId: Long) : ViewModel() {
|
||||
|
||||
@@ -10,7 +10,8 @@ import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
import kotlinx.android.synthetic.main.fragment_recycler.view.*
|
||||
import de.sebse.fuplanner2.databinding.FragmentRecyclerBinding
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -19,6 +20,7 @@ class NotificationFragment : Fragment() {
|
||||
|
||||
private lateinit var viewModel: NotificationViewModel
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var binding: FragmentRecyclerBinding
|
||||
|
||||
init {
|
||||
setHasOptionsMenu(true)
|
||||
@@ -43,7 +45,7 @@ class NotificationFragment : Fragment() {
|
||||
})
|
||||
|
||||
return inflater.inflate(R.layout.fragment_recycler, container, false).apply {
|
||||
recycler_view.apply {
|
||||
binding.recyclerView.apply {
|
||||
//setHasFixedSize(true)
|
||||
layoutManager = viewManager
|
||||
adapter = viewAdapter
|
||||
|
||||
@@ -9,15 +9,16 @@ import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.alamkanak.weekview.WeekView
|
||||
import com.alamkanak.weekview.WeekViewDisplayable
|
||||
import com.alamkanak.weekview.WeekViewEntity
|
||||
import com.alamkanak.weekview.WeekViewEvent
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.database.Event
|
||||
import de.sebse.fuplanner2.ui.schedule.MyCustomPagingAdapter.LoadMoreHandler
|
||||
import de.sebse.fuplanner2.utils.getHtmlSpannedString
|
||||
import de.sebse.fuplanner2.utils.toTimeString
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -32,7 +33,7 @@ class ScheduleFragment : Fragment() {
|
||||
|
||||
private val scheduleViewModel: ScheduleViewModel by viewModels { ScheduleViewModelFactory() }
|
||||
private var currentDate = Calendar.getInstance()
|
||||
private var weekView: WeekView<ContextEvent>? = null
|
||||
private var weekView: WeekView? = null
|
||||
|
||||
init {
|
||||
setHasOptionsMenu(true)
|
||||
@@ -48,11 +49,6 @@ class ScheduleFragment : Fragment() {
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
scheduleViewModel.eventModel.observe(viewLifecycleOwner, Observer {
|
||||
weekView?.submit(it.map { ContextEvent(requireContext(), it) })
|
||||
weekView?.notifyDataSetChanged()
|
||||
})
|
||||
|
||||
val navController = findNavController()
|
||||
var alertCourse: Course? = null
|
||||
val alertDialog = AlertDialog.Builder(requireContext())
|
||||
@@ -69,50 +65,56 @@ class ScheduleFragment : Fragment() {
|
||||
|
||||
|
||||
return inflater.inflate(R.layout.fragment_schedule, container, false).apply {
|
||||
weekView = findViewById<WeekView<ContextEvent>>(R.id.weekView).apply {
|
||||
setOnLoadMoreListener { start, end ->
|
||||
scheduleViewModel.loadBetween(start.timeInMillis, end.timeInMillis)
|
||||
}
|
||||
weekView = findViewById<WeekView>(R.id.weekView).apply {
|
||||
val pagingAdapter = MyCustomPagingAdapter(object : LoadMoreHandler {
|
||||
override fun setOnLoadMoreListener(startDate: Calendar, endDate: Calendar) =
|
||||
scheduleViewModel.loadBetween(startDate.timeInMillis, endDate.timeInMillis)
|
||||
|
||||
setOnRangeChangeListener { firstVisibleDate, _ ->
|
||||
currentDate = firstVisibleDate.clone() as Calendar
|
||||
}
|
||||
override fun setOnRangeChangeListener(
|
||||
firstVisibleDate: Calendar,
|
||||
lastVisibleDate: Calendar
|
||||
) {
|
||||
currentDate = firstVisibleDate.clone() as Calendar
|
||||
}
|
||||
|
||||
setOnEventClickListener { data, _ ->
|
||||
alertDialog.run {
|
||||
GlobalScope.launch {
|
||||
val course: Course? = withContext(Dispatchers.IO) {
|
||||
AppDatabase.getInstance().courseDao().getCourseById2(data.event.courseId)
|
||||
}
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
val cs: CharSequence = SpannableStringBuilder().apply {
|
||||
if (course != null) {
|
||||
override fun setOnEventClickListener(data: ContextEvent) {
|
||||
alertDialog.run {
|
||||
GlobalScope.launch {
|
||||
val course: Course = withContext(Dispatchers.IO) {
|
||||
AppDatabase.getInstance().courseDao().getCourseById2(data.event.courseId)
|
||||
}
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
val cs: CharSequence = SpannableStringBuilder().apply {
|
||||
this.append(context.getHtmlSpannedString(R.string.dialog_course_br, course.title))
|
||||
if (!data.event.location.isNullOrBlank()) {
|
||||
this.append(context.getHtmlSpannedString(R.string.dialog_location_br, data.event.location))
|
||||
}
|
||||
this.append(context.getHtmlSpannedString(
|
||||
R.string.dialog_time,
|
||||
data.event.startDateTime.toTimeString(context),
|
||||
(data.event.startDateTime + data.event.duration).toTimeString(context)
|
||||
))
|
||||
}
|
||||
if (!data.event.location.isNullOrBlank()) {
|
||||
this.append(context.getHtmlSpannedString(R.string.dialog_location_br, data.event.location))
|
||||
withContext(Dispatchers.Main) {
|
||||
alertCourse = course
|
||||
setTitle(data.event.title)
|
||||
setMessage(cs)
|
||||
show()
|
||||
}
|
||||
this.append(context.getHtmlSpannedString(
|
||||
R.string.dialog_time,
|
||||
data.event.startDateTime.toTimeString(context),
|
||||
(data.event.startDateTime + data.event.duration).toTimeString(context)
|
||||
))
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
alertCourse = course
|
||||
setTitle(data.event.title)
|
||||
setMessage(cs)
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
scheduleViewModel.eventModel.observe(viewLifecycleOwner, {
|
||||
pagingAdapter.updateEntries(it.map { event -> ContextEvent(requireContext(), event) })
|
||||
})
|
||||
|
||||
val todayDate = Calendar.getInstance()
|
||||
todayDate.firstDayOfWeek = Calendar.SATURDAY
|
||||
todayDate.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY)
|
||||
todayDate.add(Calendar.DAY_OF_WEEK, 2)
|
||||
goToDate(todayDate)
|
||||
scrollToDate(todayDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,18 +126,18 @@ class ScheduleFragment : Fragment() {
|
||||
currentDate.firstDayOfWeek = Calendar.TUESDAY
|
||||
currentDate.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY)
|
||||
currentDate.add(Calendar.DAY_OF_WEEK, -1)
|
||||
weekView?.goToDate(currentDate)
|
||||
weekView?.scrollToDate(currentDate)
|
||||
true
|
||||
}
|
||||
R.id.next_week -> {
|
||||
currentDate.firstDayOfWeek = Calendar.MONDAY
|
||||
currentDate.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
|
||||
currentDate.add(Calendar.DAY_OF_WEEK, 7)
|
||||
weekView?.goToDate(currentDate)
|
||||
weekView?.scrollToDate(currentDate)
|
||||
true
|
||||
}
|
||||
R.id.go_to_today -> {
|
||||
weekView?.goToToday()
|
||||
weekView?.scrollToDate(Calendar.getInstance())
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
@@ -143,22 +145,21 @@ class ScheduleFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
data class ContextEvent(val actCtx: Context, val event: Event): WeekViewDisplayable<ContextEvent> {
|
||||
override fun toWeekViewEvent(): WeekViewEvent<ContextEvent> {
|
||||
data class ContextEvent(val actCtx: Context, val event: Event) {
|
||||
fun toWeekViewEvent(): WeekViewEntity {
|
||||
// Build the styling of the event, for instance background color and strike-through
|
||||
val style = WeekViewEvent.Style.Builder()
|
||||
val style = WeekViewEntity.Style.Builder()
|
||||
.setBackgroundColor(getColor(actCtx, event.courseId))
|
||||
.setTextStrikeThrough(false)
|
||||
.setTextColorResource(R.color.scheduleOtherText)
|
||||
.build()
|
||||
|
||||
// Build the WeekViewEvent via the Builder
|
||||
return WeekViewEvent.Builder(this)
|
||||
return WeekViewEntity.Event.Builder(this)
|
||||
.setId(event.getHash().toLong())
|
||||
.setTitle(event.title)
|
||||
.setStartTime(Calendar.getInstance().apply { timeInMillis = event.startDateTime })
|
||||
.setEndTime(Calendar.getInstance().apply { timeInMillis = event.startDateTime + event.duration })
|
||||
.setLocation(event.location ?: "")
|
||||
.setSubtitle(event.location ?: "")
|
||||
.setAllDay(false)
|
||||
.setStyle(style)
|
||||
.build()
|
||||
@@ -214,3 +215,35 @@ data class ContextEvent(val actCtx: Context, val event: Event): WeekViewDisplaya
|
||||
return 0xFF000000.toInt() + (r*0xFF).roundToInt() * 0x10000 + (g*0xFF).roundToInt() * 0x100 + (b*0xFF).roundToInt()
|
||||
}
|
||||
}
|
||||
|
||||
class MyCustomPagingAdapter(
|
||||
private val loadMoreHandler: LoadMoreHandler
|
||||
) : WeekView.PagingAdapter<ContextEvent>() {
|
||||
|
||||
interface LoadMoreHandler {
|
||||
fun setOnLoadMoreListener(startDate: Calendar, endDate: Calendar)
|
||||
fun setOnRangeChangeListener(firstVisibleDate: Calendar, lastVisibleDate: Calendar)
|
||||
fun setOnEventClickListener(data: ContextEvent)
|
||||
}
|
||||
|
||||
override fun onCreateEntity(item: ContextEvent): WeekViewEntity {
|
||||
return item.toWeekViewEvent()
|
||||
}
|
||||
|
||||
override fun onLoadMore(startDate: Calendar, endDate: Calendar) {
|
||||
loadMoreHandler.setOnLoadMoreListener(startDate, endDate)
|
||||
}
|
||||
|
||||
override fun onRangeChanged(firstVisibleDate: Calendar, lastVisibleDate: Calendar) {
|
||||
loadMoreHandler.setOnRangeChangeListener(firstVisibleDate, lastVisibleDate)
|
||||
}
|
||||
|
||||
override fun onEventClick(data: ContextEvent) {
|
||||
loadMoreHandler.setOnEventClickListener(data)
|
||||
}
|
||||
|
||||
fun updateEntries(elements: List<ContextEvent>) {
|
||||
this.submitList(elements)
|
||||
this.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ScheduleViewModelFactory(): ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T = ScheduleViewModel() as T
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = ScheduleViewModel() as T
|
||||
}
|
||||
|
||||
class ScheduleViewModel() : ViewModel() {
|
||||
|
||||
@@ -40,7 +40,7 @@ object Whiteboard: FUAuthModule() {
|
||||
override suspend fun login(ctx: Context, name: String, password: String, user: User) {
|
||||
val requester = Requester(ctx)
|
||||
val request = requester.get(LOGIN_URL, cookies = getCookies(user, shib = true))
|
||||
val samlUri = request.headers["Location"]
|
||||
val samlUri = request.headers?.get("Location")
|
||||
?: throw invalidResponse(102100, "Location header not set!")
|
||||
if (samlUri == RESTORE_ON_REDIRECT_TO) {
|
||||
updateCookies(user, request)
|
||||
@@ -60,7 +60,7 @@ object Whiteboard: FUAuthModule() {
|
||||
updateCookies(user, response)
|
||||
// Finish BB & Start Session
|
||||
response = requester.get(
|
||||
response.networkResponse.headers["Location"] ?: throw invalidResponse(102101, "No Location header to finish Blackboard"),
|
||||
response.networkResponse.headers?.get("Location") ?: throw invalidResponse(102101, "No Location header to finish Blackboard"),
|
||||
getCookies(user, shib = true)
|
||||
)
|
||||
|
||||
@@ -77,13 +77,13 @@ object Whiteboard: FUAuthModule() {
|
||||
}
|
||||
|
||||
private fun updateCookies(user: User, response: NetData) {
|
||||
val setCookies = parseCookies(response.networkResponse.allHeaders)
|
||||
setCookies["JSESSIONID"]?.let {
|
||||
val setCookies = response.networkResponse.allHeaders?.let { parseCookies(it) }
|
||||
setCookies?.get("JSESSIONID")?.let {
|
||||
user.cookies.wbJsessionId = it
|
||||
}
|
||||
setCookies
|
||||
.filter{ (key, _) -> key.startsWith("_shibsession_") }
|
||||
.forEach { (key, value) ->
|
||||
?.filter{ (key, _) -> key.startsWith("_shibsession_") }
|
||||
?.forEach { (key, value) ->
|
||||
user.cookies.wbShibKey = key
|
||||
user.cookies.wbShibValue = value
|
||||
return@forEach
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
tools:openDrawer="start">
|
||||
|
||||
<include
|
||||
android:id="@+id/app_bar_main"
|
||||
layout="@layout/app_bar_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:showIn="@layout/app_bar_main">
|
||||
|
||||
<fragment
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/nav_host_fragment"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -11,19 +11,18 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:columnGap="0dp"
|
||||
app:headerRowPadding="12dp"
|
||||
app:headerPadding="12dp"
|
||||
app:hourHeight="45dp"
|
||||
app:maxHour="20"
|
||||
app:minHour="7"
|
||||
app:numberOfVisibleDays="5"
|
||||
app:showCompleteDay="false"
|
||||
app:showDistinctPastFutureColor="true"
|
||||
app:timeColumnPadding="8dp"
|
||||
app:timeColumnTextSize="10sp"
|
||||
app:daySeparatorColor="@color/scheduleSeparator"
|
||||
app:futureBackgroundColor="@color/scheduleFutureBackground"
|
||||
app:headerRowBackgroundColor="@color/scheduleNavBackground"
|
||||
app:headerRowTextColor="@color/scheduleOtherText"
|
||||
app:headerBackgroundColor="@color/scheduleNavBackground"
|
||||
app:headerTextColor="@color/scheduleOtherText"
|
||||
app:hourSeparatorColor="@color/scheduleSeparator"
|
||||
app:pastBackgroundColor="@color/schedulePastBackground"
|
||||
app:timeColumnBackgroundColor="@color/scheduleNavBackground"
|
||||
|
||||
11
build.gradle
11
build.gradle
@@ -1,15 +1,16 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.71'
|
||||
ext.kotlin_version = '1.5.31'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.2'
|
||||
classpath 'com.android.tools.build:gradle:7.0.3'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.2.1'
|
||||
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
@@ -19,7 +20,7 @@ buildscript {
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Sun Mar 15 15:45:08 CET 2020
|
||||
#Sun Nov 07 21:12:26 CET 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
|
||||
|
||||
Reference in New Issue
Block a user