Compare commits
No commits in common. "dev" and "master" have entirely different histories.
@ -1,12 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.androidApplication)
|
alias(libs.plugins.androidApplication)
|
||||||
alias(libs.plugins.jetbrainsKotlinAndroid)
|
alias(libs.plugins.jetbrainsKotlinAndroid)
|
||||||
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
secrets {
|
|
||||||
propertiesFileName = "secrets.properties"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -42,7 +36,6 @@ android {
|
|||||||
buildFeatures {
|
buildFeatures {
|
||||||
compose = true
|
compose = true
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
buildConfig = true
|
|
||||||
}
|
}
|
||||||
composeOptions {
|
composeOptions {
|
||||||
kotlinCompilerExtensionVersion = "1.5.1"
|
kotlinCompilerExtensionVersion = "1.5.1"
|
||||||
@ -55,10 +48,9 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
coreLibraryDesugaring(libs.desugar.jdk.libs)
|
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.5.0")
|
||||||
|
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
implementation(libs.androidx.core.splashscreen)
|
|
||||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
implementation(libs.androidx.activity.compose)
|
implementation(libs.androidx.activity.compose)
|
||||||
implementation(platform(libs.androidx.compose.bom))
|
implementation(platform(libs.androidx.compose.bom))
|
||||||
@ -79,19 +71,16 @@ dependencies {
|
|||||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||||
debugImplementation(libs.androidx.ui.tooling)
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
|
|
||||||
implementation(libs.androidx.navigation.compose)
|
implementation(libs.androidx.navigation.compose)
|
||||||
|
|
||||||
implementation(libs.ktor.client.core)
|
implementation(libs.ktor.client.core)
|
||||||
implementation(libs.ktor.client.cio)
|
implementation(libs.ktor.client.cio)
|
||||||
implementation(libs.ktor.client.logging)
|
implementation(libs.ktor.client.logging)
|
||||||
implementation(libs.coil.compose)
|
|
||||||
|
|
||||||
implementation(libs.androidx.datastore.preferences)
|
implementation(libs.androidx.datastore.preferences)
|
||||||
implementation(libs.splitties.funpack.android.base.with.views.dsl)
|
implementation("com.louiscad.splitties:splitties-fun-pack-android-base-with-views-dsl:3.0.0")
|
||||||
|
|
||||||
implementation(libs.compose)
|
implementation("com.kizitonwose.calendar:compose:2.5.0")
|
||||||
|
|
||||||
implementation(libs.kefirbb)
|
|
||||||
|
|
||||||
implementation(libs.acra.http)
|
|
||||||
}
|
}
|
@ -5,10 +5,9 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".ui.UNNApp"
|
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:label="@string/app_name"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.UNN"
|
android:theme="@style/Theme.UNN"
|
||||||
@ -16,10 +15,6 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ui.layout.MainActivity"
|
android:name=".ui.layout.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/Theme.UNN" />
|
|
||||||
<activity
|
|
||||||
android:name=".ui.layout.LoginActivity"
|
|
||||||
android:exported="true"
|
|
||||||
android:theme="@style/Theme.UNN">
|
android:theme="@style/Theme.UNN">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@ -27,6 +22,10 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.layout.LoginActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:theme="@style/Theme.UNN"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 48 KiB |
@ -1,29 +1,24 @@
|
|||||||
package ru.sweetbread.unn.ui
|
package ru.sweetbread.unn.ui
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import io.ktor.client.request.forms.submitForm
|
import io.ktor.client.request.forms.submitForm
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
import io.ktor.client.request.header
|
|
||||||
import io.ktor.client.request.parameter
|
import io.ktor.client.request.parameter
|
||||||
import io.ktor.client.statement.bodyAsText
|
import io.ktor.client.statement.bodyAsText
|
||||||
import io.ktor.http.parameters
|
import io.ktor.http.parameters
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import ru.sweetbread.unn.R
|
|
||||||
import ru.sweetbread.unn.ui.layout.LoginData
|
import ru.sweetbread.unn.ui.layout.LoginData
|
||||||
import ru.sweetbread.unn.ui.layout.client
|
import ru.sweetbread.unn.ui.layout.client
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
private lateinit var PHPSESSID: String
|
private lateinit var PHPSESSID: String
|
||||||
private lateinit var CSRF: String
|
|
||||||
lateinit var ME: User
|
lateinit var ME: User
|
||||||
|
|
||||||
const val portalURL = "https://portal.unn.ru"
|
const val portalURL = "https://portal.unn.ru"
|
||||||
const val ruzapiURL = "$portalURL/ruzapi"
|
const val ruzapiURL = "$portalURL/ruzapi"
|
||||||
const val vuzapiURL = "$portalURL/bitrix/vuz/api"
|
|
||||||
const val restURL = "$portalURL/rest"
|
|
||||||
|
|
||||||
enum class Type(val s: String) {
|
enum class Type(val s: String) {
|
||||||
Student("student"),
|
Student("student"),
|
||||||
@ -32,14 +27,12 @@ enum class Type(val s: String) {
|
|||||||
Auditorium("auditorium")
|
Auditorium("auditorium")
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class LecturerRank(val id: Int) {
|
enum class LecturerRank(val s: String) {
|
||||||
Assistant(R.string.assistant),
|
Lecturer("Lecturer"),
|
||||||
Lecturer(R.string.lecturer),
|
SLecturer("Senior Lecturer")
|
||||||
SLecturer(R.string.slecturer),
|
|
||||||
AProfessor(R.string.aprofessor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScheduleUnit(val oid: Int,
|
class ScheduleUnit(
|
||||||
val auditorium: Auditorium,
|
val auditorium: Auditorium,
|
||||||
val date: LocalDate,
|
val date: LocalDate,
|
||||||
val discipline: Discipline,
|
val discipline: Discipline,
|
||||||
@ -49,56 +42,40 @@ class ScheduleUnit(val oid: Int,
|
|||||||
val begin: LocalTime,
|
val begin: LocalTime,
|
||||||
val end: LocalTime)
|
val end: LocalTime)
|
||||||
|
|
||||||
class Auditorium( val name: String,
|
class Auditorium (val name: String,
|
||||||
val oid: Int,
|
val oid: Int,
|
||||||
val floor: Int,
|
val floor: Int,
|
||||||
val building: Building)
|
val building: Building)
|
||||||
class Building( val name: String,
|
class Building(val name: String,
|
||||||
val gid: Int,
|
val gid: Int,
|
||||||
val oid: Int)
|
val oid: Int)
|
||||||
|
|
||||||
class Discipline( val name: String,
|
class Discipline (val name: String,
|
||||||
val oid: Int,
|
val oid: Int,
|
||||||
val type: Int)
|
val type: Int)
|
||||||
|
|
||||||
class KindOfWork( val name: String,
|
class KindOfWork (val name: String,
|
||||||
val oid: Int,
|
val oid: Int,
|
||||||
val uid: String,
|
val uid: String,
|
||||||
val complexity: Int)
|
val complexity: Int)
|
||||||
|
|
||||||
class Lecturer( val name: String,
|
class Lecturer (val name: String,
|
||||||
val rank: LecturerRank,
|
val rank: LecturerRank,
|
||||||
val email: String,
|
val email: String,
|
||||||
val unnId: Int,
|
val oid: Int,
|
||||||
val uid: String)
|
val uid: String)
|
||||||
|
|
||||||
class User (val unnId: Int?,
|
class User (val id: String,
|
||||||
val bitrixId: Int,
|
val uns: String,
|
||||||
val userId: Int,
|
|
||||||
val type: Type,
|
val type: Type,
|
||||||
val email: String,
|
val email: String,
|
||||||
val nameRu: String,
|
val name: String,
|
||||||
val nameEn: String,
|
val info: String)
|
||||||
val isMale: Boolean,
|
|
||||||
val birthday: LocalDate,
|
|
||||||
val avatar: ImageSet)
|
|
||||||
|
|
||||||
class Post(
|
|
||||||
val id: Int,
|
|
||||||
val authorId: Int,
|
|
||||||
val enableComments: Boolean,
|
|
||||||
val numComments: Int,
|
|
||||||
val date: LocalDateTime,
|
|
||||||
val content: String)
|
|
||||||
|
|
||||||
class ImageSet(val original: String,
|
|
||||||
val thumbnail: String,
|
|
||||||
val small: String)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorize user by [login] and [password]
|
* Authorize user by [login] and [password]
|
||||||
*
|
*
|
||||||
* Also defines local vars [PHPSESSID] and [ME]
|
* Also defines local vars [PHPSESSID] and [ME.id]
|
||||||
*/
|
*/
|
||||||
suspend fun auth(login: String = LoginData.login, password: String = LoginData.password, forced: Boolean = false): Boolean {
|
suspend fun auth(login: String = LoginData.login, password: String = LoginData.password, forced: Boolean = false): Boolean {
|
||||||
if (!forced) {
|
if (!forced) {
|
||||||
@ -117,67 +94,36 @@ suspend fun auth(login: String = LoginData.login, password: String = LoginData.p
|
|||||||
if (r.status.value == 302) {
|
if (r.status.value == 302) {
|
||||||
PHPSESSID = """PHPSESSID=([\w\d]+)""".toRegex().find(r.headers["Set-Cookie"]!!)!!.groupValues[1]
|
PHPSESSID = """PHPSESSID=([\w\d]+)""".toRegex().find(r.headers["Set-Cookie"]!!)!!.groupValues[1]
|
||||||
getMyself(login)
|
getMyself(login)
|
||||||
getCSRF()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Save info about current [User] in memory
|
|
||||||
*/
|
|
||||||
private suspend fun getMyself(login: String) {
|
private suspend fun getMyself(login: String) {
|
||||||
val studentinfo = JSONObject(client.get("$ruzapiURL/studentinfo") {
|
val r = client.get("$ruzapiURL/studentinfo") {
|
||||||
parameter("uns", login.substring(1))
|
parameter("uns", login.substring(1))
|
||||||
}.bodyAsText())
|
}
|
||||||
|
val json = JSONObject(r.bodyAsText())
|
||||||
val user = JSONObject(
|
|
||||||
client.get("$vuzapiURL/user") {
|
|
||||||
header("Cookie", "PHPSESSID=${PHPSESSID}")
|
|
||||||
}.bodyAsText()
|
|
||||||
)
|
|
||||||
|
|
||||||
ME = User(
|
ME = User(
|
||||||
unnId = studentinfo.getString("id").toInt(),
|
id = json.getString("id"),
|
||||||
bitrixId = user.getInt("bitrix_id"),
|
uns = json.getString("uns"),
|
||||||
userId = user.getInt("id"),
|
type = when(json.getString("type")) {
|
||||||
type = when(studentinfo.getString("type")) {
|
|
||||||
"lecturer" -> Type.Lecturer // ig,,,
|
"lecturer" -> Type.Lecturer // ig,,,
|
||||||
else -> Type.Student
|
else -> Type.Student
|
||||||
},
|
},
|
||||||
email = user.getString("email"),
|
email = json.getString("email"),
|
||||||
nameRu = user.getString("fullname"),
|
name = json.getString("fio"),
|
||||||
nameEn = user.getString("fullname_en"),
|
info = json.getString("info")
|
||||||
isMale = user.getString("sex") == "M",
|
|
||||||
birthday = LocalDate.parse(
|
|
||||||
user.getString("birthdate"),
|
|
||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd")
|
|
||||||
),
|
|
||||||
avatar = user.getJSONObject("photo").let {
|
|
||||||
ImageSet(
|
|
||||||
it.getString("orig"),
|
|
||||||
it.getString("thumbnail"),
|
|
||||||
it.getString("small"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getSchedule(
|
suspend fun getSchedule(type: Type = Type.Student, id: String = ME.id, start: LocalDate, finish: LocalDate): ArrayList<ScheduleUnit> {
|
||||||
type: Type = ME.type,
|
|
||||||
id: Int = ME.unnId!!,
|
|
||||||
start: LocalDate,
|
|
||||||
finish: LocalDate
|
|
||||||
): ArrayList<ScheduleUnit> {
|
|
||||||
val unnDatePattern = DateTimeFormatter.ofPattern("yyyy.MM.dd")
|
|
||||||
|
|
||||||
val r = client.get("$ruzapiURL/schedule/${type.s}/$id") {
|
val r = client.get("$ruzapiURL/schedule/${type.s}/$id") {
|
||||||
parameter("start", start.format(unnDatePattern))
|
parameter("start", start.format(DateTimeFormatter.ofPattern("yyyy.MM.dd")))
|
||||||
parameter("finish", finish.format(unnDatePattern))
|
parameter("finish", finish.format(DateTimeFormatter.ofPattern("yyyy.MM.dd")))
|
||||||
parameter("lng", "1")
|
parameter("lng", "1")
|
||||||
}
|
}
|
||||||
val json = JSONArray(r.bodyAsText())
|
val json = JSONArray(r.bodyAsText())
|
||||||
|
|
||||||
val out = arrayListOf<ScheduleUnit>()
|
val out = arrayListOf<ScheduleUnit>()
|
||||||
for (i in 0 until json.length()) {
|
for (i in 0 until json.length()) {
|
||||||
val unit = json.getJSONObject(i)
|
val unit = json.getJSONObject(i)
|
||||||
@ -190,12 +136,10 @@ suspend fun getSchedule(
|
|||||||
Lecturer(
|
Lecturer(
|
||||||
name = lecturer.getString("lecturer"),
|
name = lecturer.getString("lecturer"),
|
||||||
email = lecturer.getString("lecturerEmail"),
|
email = lecturer.getString("lecturerEmail"),
|
||||||
unnId = lecturer.getInt("lecturerOid"),
|
oid = lecturer.getInt("lecturerOid"),
|
||||||
uid = lecturer.getString("lecturerUID"),
|
uid = lecturer.getString("lecturerUID"),
|
||||||
rank = when (lecturer.getString("lecturer_rank")) {
|
rank = when (lecturer.getString("lecturer_rank")) {
|
||||||
"АССИСТ" -> LecturerRank.Assistant
|
|
||||||
"СТПРЕП" -> LecturerRank.SLecturer
|
"СТПРЕП" -> LecturerRank.SLecturer
|
||||||
"ДОЦЕНТ" -> LecturerRank.AProfessor
|
|
||||||
else -> LecturerRank.Lecturer
|
else -> LecturerRank.Lecturer
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -204,7 +148,6 @@ suspend fun getSchedule(
|
|||||||
|
|
||||||
out.add(
|
out.add(
|
||||||
ScheduleUnit(
|
ScheduleUnit(
|
||||||
oid = unit.getInt("lessonOid"),
|
|
||||||
auditorium = Auditorium(
|
auditorium = Auditorium(
|
||||||
name = unit.getString("auditorium"),
|
name = unit.getString("auditorium"),
|
||||||
oid = unit.getInt("auditoriumOid"),
|
oid = unit.getInt("auditoriumOid"),
|
||||||
@ -215,7 +158,7 @@ suspend fun getSchedule(
|
|||||||
oid = unit.getInt("buildingOid")
|
oid = unit.getInt("buildingOid")
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
date = LocalDate.parse(unit.getString("date"), unnDatePattern),
|
date = LocalDate.parse(unit.getString("date"), DateTimeFormatter.ofPattern("yyyy.MM.dd")),
|
||||||
discipline = Discipline(
|
discipline = Discipline(
|
||||||
name = unit.getString("discipline"),
|
name = unit.getString("discipline"),
|
||||||
oid = unit.getInt("disciplineOid"),
|
oid = unit.getInt("disciplineOid"),
|
||||||
@ -236,79 +179,3 @@ suspend fun getSchedule(
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getCSRF() {
|
|
||||||
val r = client.get("$restURL/log.blogpost.get") {
|
|
||||||
header("Cookie", "PHPSESSID=${PHPSESSID}")
|
|
||||||
parameter("sessid", "")
|
|
||||||
}
|
|
||||||
CSRF = JSONObject(r.bodyAsText()).getString("sessid")
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getBlogposts(): ArrayList<Post> {
|
|
||||||
val r = client.get("$restURL/log.blogpost.get") {
|
|
||||||
header("Cookie", "PHPSESSID=${PHPSESSID}")
|
|
||||||
parameter("sessid", CSRF)
|
|
||||||
}
|
|
||||||
val json = JSONObject(r.bodyAsText())
|
|
||||||
val result = json.getJSONArray("result")
|
|
||||||
|
|
||||||
val out = arrayListOf<Post>()
|
|
||||||
for (i in 0 until result.length()) {
|
|
||||||
val el = result.getJSONObject(i)
|
|
||||||
out.add(
|
|
||||||
Post(
|
|
||||||
id = el.getString("ID").toInt(),
|
|
||||||
authorId = el.getString("AUTHOR_ID").toInt(),
|
|
||||||
enableComments = el.getString("ENABLE_COMMENTS") == "Y",
|
|
||||||
numComments = el.getString("NUM_COMMENTS").toInt(),
|
|
||||||
date = LocalDateTime.parse(
|
|
||||||
el.getString("DATE_PUBLISH"),
|
|
||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'+03:00'")
|
|
||||||
),
|
|
||||||
content = el.getString("DETAIL_TEXT")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getUserByBitrixId(id: Int): User {
|
|
||||||
val userId = JSONObject(client.get("$vuzapiURL/user/bx/$id") {
|
|
||||||
header("Cookie", "PHPSESSID=${PHPSESSID}")
|
|
||||||
}.bodyAsText()).getInt("id")
|
|
||||||
return getUser(userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getUser(id: Int): User {
|
|
||||||
val json = JSONObject(
|
|
||||||
client.get("$vuzapiURL/user/$id") {
|
|
||||||
header("Cookie", "PHPSESSID=${PHPSESSID}")
|
|
||||||
}.bodyAsText()
|
|
||||||
)
|
|
||||||
|
|
||||||
return User(
|
|
||||||
unnId = null,
|
|
||||||
bitrixId = json.getInt("bitrix_id"),
|
|
||||||
userId = json.getInt("id"),
|
|
||||||
type = when (json.getJSONArray("profiles").getJSONObject(0).getString("type")) {
|
|
||||||
"lecturer" -> Type.Lecturer // ig,,,
|
|
||||||
else -> Type.Student
|
|
||||||
},
|
|
||||||
email = json.getString("email"),
|
|
||||||
nameRu = json.getString("fullname"),
|
|
||||||
nameEn = json.getString("fullname_en"),
|
|
||||||
isMale = json.getString("sex") == "M",
|
|
||||||
birthday = LocalDate.parse(
|
|
||||||
json.getString("birthdate"),
|
|
||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd")
|
|
||||||
),
|
|
||||||
avatar = json.getJSONObject("photo").let {
|
|
||||||
ImageSet(
|
|
||||||
it.getString("orig"),
|
|
||||||
it.getString("thumbnail"),
|
|
||||||
it.getString("small"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
package ru.sweetbread.unn.ui
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
|
||||||
import org.acra.config.httpSender
|
|
||||||
import org.acra.data.StringFormat
|
|
||||||
import org.acra.ktx.initAcra
|
|
||||||
import org.acra.sender.HttpSender
|
|
||||||
import ru.sweetbread.unn.BuildConfig
|
|
||||||
|
|
||||||
class UNNApp : Application() {
|
|
||||||
override fun attachBaseContext(base: Context) {
|
|
||||||
super.attachBaseContext(base)
|
|
||||||
|
|
||||||
initAcra {
|
|
||||||
buildConfigClass = BuildConfig::class.java
|
|
||||||
reportFormat = StringFormat.JSON
|
|
||||||
httpSender {
|
|
||||||
uri = BuildConfig.ACRA_URL
|
|
||||||
basicAuthLogin = BuildConfig.ACRA_LOGIN
|
|
||||||
basicAuthPassword = BuildConfig.ACRA_PASS
|
|
||||||
httpMethod = HttpSender.Method.POST
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,261 +0,0 @@
|
|||||||
package ru.sweetbread.unn.ui.composes
|
|
||||||
|
|
||||||
import android.text.util.Linkify
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material3.HorizontalDivider
|
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.NonRestartableComposable
|
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.toArgb
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
|
||||||
import androidx.core.text.HtmlCompat
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import coil.compose.AsyncImage
|
|
||||||
import com.google.android.material.textview.MaterialTextView
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import org.kefirsf.bb.BBProcessorFactory
|
|
||||||
import org.kefirsf.bb.TextProcessor
|
|
||||||
import ru.sweetbread.unn.R
|
|
||||||
import ru.sweetbread.unn.ui.ImageSet
|
|
||||||
import ru.sweetbread.unn.ui.Post
|
|
||||||
import ru.sweetbread.unn.ui.Type
|
|
||||||
import ru.sweetbread.unn.ui.User
|
|
||||||
import ru.sweetbread.unn.ui.getBlogposts
|
|
||||||
import ru.sweetbread.unn.ui.getUserByBitrixId
|
|
||||||
import ru.sweetbread.unn.ui.portalURL
|
|
||||||
import ru.sweetbread.unn.ui.theme.UNNTheme
|
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
import java.time.format.FormatStyle
|
|
||||||
|
|
||||||
|
|
||||||
val defUser = User(
|
|
||||||
null,
|
|
||||||
123,
|
|
||||||
123,
|
|
||||||
Type.Student,
|
|
||||||
"cool.email@domain.com",
|
|
||||||
"Джон Сигма Омегович",
|
|
||||||
"Jon Sigma Omega",
|
|
||||||
true,
|
|
||||||
LocalDate.now(),
|
|
||||||
ImageSet(
|
|
||||||
"https://upload.wikimedia.org/wikipedia/ru/thumb/9/94/%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg/500px-%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg",
|
|
||||||
"https://upload.wikimedia.org/wikipedia/ru/thumb/9/94/%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg/500px-%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg",
|
|
||||||
"https://upload.wikimedia.org/wikipedia/ru/thumb/9/94/%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg/500px-%D0%93%D0%B8%D0%B3%D0%B0%D1%87%D0%B0%D0%B4.jpg"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Blogposts(viewModel: PostViewModel = viewModel()) {
|
|
||||||
val posts by viewModel.posts.collectAsState()
|
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
viewModel.loadPosts()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (posts.isNotEmpty()) {
|
|
||||||
Log.d("Another fuck", posts.size.toString())
|
|
||||||
LazyColumn {
|
|
||||||
items(posts) {
|
|
||||||
PostItem(
|
|
||||||
Modifier
|
|
||||||
.padding(8.dp)
|
|
||||||
.clip(RoundedCornerShape(16.dp))
|
|
||||||
.background(MaterialTheme.colorScheme.secondaryContainer),
|
|
||||||
post = it
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LinearProgressIndicator(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(8.dp),
|
|
||||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
|
||||||
trackColor = MaterialTheme.colorScheme.secondary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PostRepository {
|
|
||||||
suspend fun loadPosts(): List<Post> {
|
|
||||||
return getBlogposts()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PostViewModel : ViewModel() {
|
|
||||||
private val repository = PostRepository()
|
|
||||||
private val _posts = MutableStateFlow<List<Post>>(emptyList())
|
|
||||||
val posts: StateFlow<List<Post>> = _posts.asStateFlow()
|
|
||||||
|
|
||||||
suspend fun loadPosts() {
|
|
||||||
_posts.value = repository.loadPosts()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@NonRestartableComposable
|
|
||||||
fun UserItem(modifier: Modifier = Modifier, user: User, info: String? = null) {
|
|
||||||
Row(
|
|
||||||
modifier.padding(16.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
|
||||||
) {
|
|
||||||
AsyncImage(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = 8.dp)
|
|
||||||
.size(48.dp)
|
|
||||||
.clip(RoundedCornerShape(50)),
|
|
||||||
model = portalURL + user.avatar.thumbnail,
|
|
||||||
contentDescription = user.nameEn
|
|
||||||
)
|
|
||||||
|
|
||||||
Column {
|
|
||||||
Text(user.nameRu, fontWeight = FontWeight.Bold)
|
|
||||||
if (!info.isNullOrBlank())
|
|
||||||
Text(
|
|
||||||
text = info,
|
|
||||||
fontStyle = FontStyle.Italic,
|
|
||||||
fontSize = MaterialTheme.typography.labelLarge.fontSize
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@NonRestartableComposable
|
|
||||||
fun PostItem(modifier: Modifier = Modifier, post: Post) {
|
|
||||||
var user: User? by remember { mutableStateOf(null) }
|
|
||||||
val processor = remember { BBProcessorFactory.getInstance().create() }
|
|
||||||
var html: String by remember { mutableStateOf("") }
|
|
||||||
|
|
||||||
|
|
||||||
LaunchedEffect(post) {
|
|
||||||
html = toHtml(processor, post)
|
|
||||||
user = getUserByBitrixId(post.authorId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(modifier.padding(16.dp)) {
|
|
||||||
if (user != null)
|
|
||||||
UserItem(user = user!!)
|
|
||||||
else
|
|
||||||
LinearProgressIndicator(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(8.dp),
|
|
||||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
|
||||||
trackColor = MaterialTheme.colorScheme.secondary,
|
|
||||||
)
|
|
||||||
|
|
||||||
AndroidView(
|
|
||||||
factory = {
|
|
||||||
MaterialTextView(it).apply {
|
|
||||||
autoLinkMask = Linkify.WEB_URLS
|
|
||||||
linksClickable = true
|
|
||||||
setLinkTextColor(Color.White.toArgb())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
update = {
|
|
||||||
it.maxLines = 25
|
|
||||||
it.text = HtmlCompat.fromHtml(html, 0)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
HorizontalDivider(
|
|
||||||
modifier = Modifier.padding(vertical = 16.dp),
|
|
||||||
thickness = 1.dp,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(text = post.date.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toHtml(
|
|
||||||
processor: TextProcessor,
|
|
||||||
post: Post
|
|
||||||
): String {
|
|
||||||
val html = processor.process(post.content)
|
|
||||||
return html.replace("""\[URL=(.+)](.+)\[/URL]""".toRegex()) {
|
|
||||||
Log.d("replace", it.groups.toString())
|
|
||||||
"<a href='${it.groups[1]?.value}'>${it.groups[2]?.value}</a>"
|
|
||||||
}.replace("""(\[FONT=.+]|\[CENTER])(.+)(\[/FONT]|\[/CENTER])""".toRegex()) {
|
|
||||||
it.groups[2]?.value.toString()
|
|
||||||
}.replace("""\[IMG .+].+\[/IMG]""".toRegex(), "")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun UserItemPreview() {
|
|
||||||
UNNTheme {
|
|
||||||
Surface {
|
|
||||||
UserItem(
|
|
||||||
Modifier
|
|
||||||
.width(300.dp)
|
|
||||||
.clip(RoundedCornerShape(8.dp))
|
|
||||||
.background(MaterialTheme.colorScheme.primaryContainer), defUser, Type.Student.s
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun PostItemPreview() {
|
|
||||||
val post = Post(
|
|
||||||
id = 154923,
|
|
||||||
authorId = 165945,
|
|
||||||
enableComments = true,
|
|
||||||
numComments = 0,
|
|
||||||
date = LocalDateTime.of(2024, 3, 20, 18, 55, 20),
|
|
||||||
content = stringResource(id = R.string.lorem)
|
|
||||||
)
|
|
||||||
|
|
||||||
UNNTheme {
|
|
||||||
Surface {
|
|
||||||
PostItem(
|
|
||||||
Modifier
|
|
||||||
.clip(RoundedCornerShape(8.dp))
|
|
||||||
.background(MaterialTheme.colorScheme.primaryContainer), post
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,8 @@
|
|||||||
package ru.sweetbread.unn.ui.composes
|
package ru.sweetbread.unn.ui.composes
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@ -15,7 +13,6 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.HorizontalDivider
|
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
@ -23,7 +20,6 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
@ -31,7 +27,6 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
@ -41,7 +36,6 @@ import com.kizitonwose.calendar.compose.WeekCalendar
|
|||||||
import com.kizitonwose.calendar.compose.weekcalendar.rememberWeekCalendarState
|
import com.kizitonwose.calendar.compose.weekcalendar.rememberWeekCalendarState
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.sweetbread.unn.R
|
|
||||||
import ru.sweetbread.unn.ui.Auditorium
|
import ru.sweetbread.unn.ui.Auditorium
|
||||||
import ru.sweetbread.unn.ui.Building
|
import ru.sweetbread.unn.ui.Building
|
||||||
import ru.sweetbread.unn.ui.Discipline
|
import ru.sweetbread.unn.ui.Discipline
|
||||||
@ -53,14 +47,13 @@ import ru.sweetbread.unn.ui.getSchedule
|
|||||||
import ru.sweetbread.unn.ui.theme.UNNTheme
|
import ru.sweetbread.unn.ui.theme.UNNTheme
|
||||||
import java.time.DayOfWeek
|
import java.time.DayOfWeek
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Schedule() {
|
fun Schedule() {
|
||||||
val state = rememberWeekCalendarState(
|
val state = rememberWeekCalendarState(
|
||||||
firstDayOfWeek = DayOfWeek.MONDAY // TODO: set start and end weeks to September and July of current year
|
firstDayOfWeek = DayOfWeek.MONDAY
|
||||||
)
|
)
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@ -73,10 +66,14 @@ fun Schedule() {
|
|||||||
.padding(vertical = 16.dp)
|
.padding(vertical = 16.dp)
|
||||||
.aspectRatio(1f) // This is important for square sizing!
|
.aspectRatio(1f) // This is important for square sizing!
|
||||||
.offset(2.dp)
|
.offset(2.dp)
|
||||||
.background(if (it.date == curDate) MaterialTheme.colorScheme.inversePrimary else MaterialTheme.colorScheme.surfaceContainer)
|
.background(if (it.date == curDate) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.secondaryContainer)
|
||||||
.clickable(
|
.clickable(
|
||||||
onClick = { curDate = it.date },
|
onClick = {
|
||||||
enabled = curDate != it.date
|
curDate = it.date
|
||||||
|
Log.d("Here bug (olClick)",
|
||||||
|
curDate.format(DateTimeFormatter.ISO_DATE)
|
||||||
|
)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
@ -96,16 +93,12 @@ fun ScheduleDay(modifier: Modifier = Modifier, date: LocalDate) {
|
|||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
var loadedDate by remember { mutableStateOf(LocalDate.MIN) }
|
var loadedDate by remember { mutableStateOf(LocalDate.MIN) }
|
||||||
val lessons = remember { mutableListOf<ScheduleUnit>() }
|
val lessons = remember { mutableListOf<ScheduleUnit>() }
|
||||||
var expanded by remember { mutableIntStateOf(0) }
|
|
||||||
|
|
||||||
if (loadedDate == date) {
|
if (loadedDate == date) {
|
||||||
Log.d("Loaded", "${date.format(DateTimeFormatter.ISO_DATE)} ${lessons.size}")
|
Log.d("Loaded", "${date.format(DateTimeFormatter.ISO_DATE)} ${lessons.size}")
|
||||||
LazyColumn (modifier) {
|
LazyColumn (modifier) {
|
||||||
items(lessons) { // TODO: Add empty list notification
|
items(lessons) {
|
||||||
ScheduleItem(unit = it, modifier = Modifier.clickable {
|
ScheduleItem(unit = it)
|
||||||
expanded = if (it.oid == expanded) 0
|
|
||||||
else it.oid
|
|
||||||
}, expanded = expanded == it.oid)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -121,143 +114,51 @@ fun ScheduleDay(modifier: Modifier = Modifier, date: LocalDate) {
|
|||||||
lessons.clear()
|
lessons.clear()
|
||||||
lessons.addAll(getSchedule(start = date, finish = date))
|
lessons.addAll(getSchedule(start = date, finish = date))
|
||||||
loadedDate = date
|
loadedDate = date
|
||||||
|
Log.d("Loading", "${date.format(DateTimeFormatter.ISO_DATE)} ${lessons.size}")
|
||||||
|
Log.d("Here bug", "${loadedDate.format(DateTimeFormatter.ISO_DATE)} ${date.format(DateTimeFormatter.ISO_DATE)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ScheduleItem(modifier: Modifier = Modifier, unit: ScheduleUnit, expanded: Boolean = false) {
|
fun ScheduleItem(modifier: Modifier = Modifier, unit: ScheduleUnit) {
|
||||||
val begin = unit.begin.format(DateTimeFormatter.ofPattern("HH:mm"))
|
|
||||||
val end = unit.end.format(DateTimeFormatter.ofPattern("HH:mm"))
|
|
||||||
|
|
||||||
Row (
|
Row (
|
||||||
modifier
|
modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(4.dp)
|
.padding(4.dp)
|
||||||
.clip(RoundedCornerShape(8.dp))
|
.clip(RoundedCornerShape(8.dp))
|
||||||
.background(
|
.background(MaterialTheme.colorScheme.primaryContainer)
|
||||||
if ((LocalDateTime.of(
|
|
||||||
unit.date,
|
|
||||||
unit.begin
|
|
||||||
) < LocalDateTime.now()) and (LocalDateTime.now() < LocalDateTime.of(
|
|
||||||
unit.date,
|
|
||||||
unit.end
|
|
||||||
))
|
|
||||||
)
|
|
||||||
MaterialTheme.colorScheme.primaryContainer
|
|
||||||
else MaterialTheme.colorScheme.secondaryContainer
|
|
||||||
)
|
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
){
|
){
|
||||||
Column (Modifier.weight(1f)) {
|
Column (Modifier.weight(1f)) {
|
||||||
Column {
|
|
||||||
Text(
|
Text(
|
||||||
text = unit.discipline.name,
|
text = unit.discipline.name,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
modifier = Modifier.zIndex(1f),
|
modifier = Modifier.zIndex(1f),
|
||||||
maxLines = if (expanded) Int.MAX_VALUE else 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility (expanded) {
|
|
||||||
HorizontalDivider(
|
|
||||||
modifier = Modifier.padding(vertical = 16.dp),
|
|
||||||
thickness = 1.dp,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
Text(
|
|
||||||
text = unit.kindOfWork.name,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
AnimatedVisibility (expanded) {
|
|
||||||
Text(text = unit.stream)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility (expanded) {
|
|
||||||
HorizontalDivider(
|
|
||||||
modifier = Modifier.padding(vertical = 16.dp),
|
|
||||||
thickness = 1.dp,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility (!expanded) {
|
|
||||||
Row(Modifier) {
|
|
||||||
Text(
|
|
||||||
text = unit.auditorium.name,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
modifier = Modifier.padding(end = 4.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = unit.auditorium.building.name,
|
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
|
Text(text = unit.kindOfWork.name, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||||
|
Row (Modifier) {
|
||||||
|
Text(text = unit.auditorium.name, fontWeight = FontWeight.Bold, modifier = Modifier.padding(end = 4.dp))
|
||||||
|
Text(text = unit.auditorium.building.name, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AnimatedVisibility (expanded) {
|
|
||||||
Column {
|
|
||||||
Text(
|
|
||||||
text = "${stringResource(R.string.auditorium)}: ${unit.auditorium.name}",
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
modifier = Modifier.padding(end = 4.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "${stringResource(R.string.building)}: ${unit.auditorium.building.name}",
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
if (unit.auditorium.floor != 0) {
|
|
||||||
Text(
|
|
||||||
text = "${stringResource(R.string.floor)}: ${unit.auditorium.floor}",
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalDivider(
|
|
||||||
modifier = Modifier.padding(vertical = 16.dp),
|
|
||||||
thickness = 1.dp,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground
|
|
||||||
)
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Text(text = unit.lecturers[0].name, fontWeight = FontWeight.Bold)
|
val begin = unit.begin.format(DateTimeFormatter.ofPattern("HH:mm"))
|
||||||
Text(text = stringResource(unit.lecturers[0].rank.id))
|
val end = unit.end.format(DateTimeFormatter.ofPattern("HH:mm"))
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalDivider(
|
|
||||||
modifier = Modifier.padding(vertical = 16.dp),
|
|
||||||
thickness = 1.dp,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground
|
|
||||||
)
|
|
||||||
|
|
||||||
Row (Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
|
||||||
Text(begin.toString(), fontWeight = FontWeight.Bold)
|
Text(begin.toString(), fontWeight = FontWeight.Bold)
|
||||||
Text(end.toString())
|
Text(end.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility (!expanded) {
|
|
||||||
Column {
|
|
||||||
Text(begin.toString(), fontWeight = FontWeight.Bold)
|
|
||||||
Text(end.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun ScheduleItemPreview() {
|
fun ScheduleItemPreview() {
|
||||||
val unit = ScheduleUnit(
|
val unit = ScheduleUnit(
|
||||||
oid = 1,
|
|
||||||
Auditorium(
|
Auditorium(
|
||||||
name = "с/з 1(110)",
|
name = "с/з 1(110)",
|
||||||
oid = 3752,
|
oid = 3752,
|
||||||
@ -285,8 +186,8 @@ fun ScheduleItemPreview() {
|
|||||||
name = "Фамилия Имя Отчество",
|
name = "Фамилия Имя Отчество",
|
||||||
rank = LecturerRank.SLecturer,
|
rank = LecturerRank.SLecturer,
|
||||||
email = "",
|
email = "",
|
||||||
unnId = 28000,
|
oid = 28407,
|
||||||
uid = "51000"
|
uid = "51769"
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
stream = "3823Б1ПР1|3823Б1ПР2|3823Б1ПР3|3823Б1ПР4|3823Б1ПР5-В-OUP",
|
stream = "3823Б1ПР1|3823Б1ПР2|3823Б1ПР3|3823Б1ПР4|3823Б1ПР5-В-OUP",
|
||||||
@ -295,56 +196,9 @@ fun ScheduleItemPreview() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
UNNTheme {
|
UNNTheme {
|
||||||
|
// A surface container using the 'background' color from the theme
|
||||||
Surface(color = MaterialTheme.colorScheme.background) {
|
Surface(color = MaterialTheme.colorScheme.background) {
|
||||||
ScheduleItem(unit = unit)
|
ScheduleItem(unit = unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun ScheduleExpandedItemPreview() {
|
|
||||||
val unit = ScheduleUnit(
|
|
||||||
oid = 1,
|
|
||||||
Auditorium(
|
|
||||||
name = "с/з 1(110)",
|
|
||||||
oid = 3752,
|
|
||||||
floor = 0,
|
|
||||||
building = Building(
|
|
||||||
name = "Корпус 6",
|
|
||||||
gid = 30,
|
|
||||||
oid = 155
|
|
||||||
),
|
|
||||||
),
|
|
||||||
date = LocalDate.of(2024, 3, 11),
|
|
||||||
discipline = Discipline(
|
|
||||||
name = "Физическая культура и спорт (элективная дисциплина)",
|
|
||||||
oid = 67895,
|
|
||||||
type = 0
|
|
||||||
),
|
|
||||||
kindOfWork = KindOfWork(
|
|
||||||
name = "Практика (семинарские занятия)",
|
|
||||||
oid = 261,
|
|
||||||
uid = "281474976710661",
|
|
||||||
complexity = 1
|
|
||||||
),
|
|
||||||
lecturers = arrayListOf(
|
|
||||||
Lecturer(
|
|
||||||
name = "Фамилия Имя Отчество",
|
|
||||||
rank = LecturerRank.SLecturer,
|
|
||||||
email = "",
|
|
||||||
unnId = 28000,
|
|
||||||
uid = "51000"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
stream = "3823Б1ПР1|3823Б1ПР2|3823Б1ПР3|3823Б1ПР4|3823Б1ПР5-В-OUP",
|
|
||||||
begin = LocalTime.of(10, 50),
|
|
||||||
end = LocalTime.of(12, 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
UNNTheme {
|
|
||||||
Surface(color = MaterialTheme.colorScheme.background) {
|
|
||||||
ScheduleItem(unit = unit, expanded = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -36,30 +36,14 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
|
|||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import ru.sweetbread.unn.R
|
import ru.sweetbread.unn.R
|
||||||
import ru.sweetbread.unn.ui.auth
|
import ru.sweetbread.unn.ui.auth
|
||||||
import ru.sweetbread.unn.ui.theme.UNNTheme
|
import ru.sweetbread.unn.ui.theme.UNNTheme
|
||||||
import splitties.activities.start
|
import splitties.activities.start
|
||||||
import splitties.preferences.Preferences
|
|
||||||
|
|
||||||
object LoginData : Preferences("loginData") {
|
|
||||||
var login by stringPref("login", "")
|
|
||||||
var password by stringPref("password", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoginActivity : ComponentActivity() {
|
class LoginActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
if ((LoginData.login != "") and (LoginData.password != ""))
|
|
||||||
runBlocking {
|
|
||||||
if (auth()) {
|
|
||||||
start<MainActivity>()
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
UNNTheme {
|
UNNTheme {
|
||||||
Surface(
|
Surface(
|
||||||
@ -78,14 +62,13 @@ class LoginActivity : ComponentActivity() {
|
|||||||
LoginData.login = login
|
LoginData.login = login
|
||||||
LoginData.password = password
|
LoginData.password = password
|
||||||
start<MainActivity>()
|
start<MainActivity>()
|
||||||
finish()
|
|
||||||
}, {
|
}, {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|
||||||
snackbarHostState
|
snackbarHostState
|
||||||
.showSnackbar(
|
.showSnackbar(
|
||||||
message = "Error",
|
message = "Error",
|
||||||
duration = SnackbarDuration.Short
|
duration = SnackbarDuration.Long
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -4,39 +4,85 @@ import android.os.Bundle
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.AccountBox
|
import androidx.compose.material.icons.filled.AccountBox
|
||||||
import androidx.compose.material.icons.filled.DateRange
|
import androidx.compose.material.icons.filled.DateRange
|
||||||
import androidx.compose.material.icons.filled.Home
|
import androidx.compose.material.icons.filled.Home
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.NavigationBar
|
import androidx.compose.material3.NavigationBar
|
||||||
import androidx.compose.material3.NavigationBarItem
|
import androidx.compose.material3.NavigationBarItem
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.zIndex
|
||||||
|
import androidx.navigation.NavType
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import androidx.navigation.navArgument
|
||||||
|
import com.kizitonwose.calendar.compose.WeekCalendar
|
||||||
|
import com.kizitonwose.calendar.compose.weekcalendar.rememberWeekCalendarState
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.plugins.HttpRequestRetry
|
import io.ktor.client.plugins.HttpRequestRetry
|
||||||
import io.ktor.client.plugins.HttpTimeout
|
import io.ktor.client.plugins.HttpTimeout
|
||||||
import io.ktor.client.plugins.cache.HttpCache
|
import io.ktor.client.plugins.cache.HttpCache
|
||||||
import io.ktor.client.plugins.logging.LogLevel
|
import kotlinx.coroutines.Dispatchers
|
||||||
import io.ktor.client.plugins.logging.Logger
|
import kotlinx.coroutines.launch
|
||||||
import io.ktor.client.plugins.logging.Logging
|
import kotlinx.coroutines.runBlocking
|
||||||
import ru.sweetbread.unn.ui.composes.Blogposts
|
import ru.sweetbread.unn.ui.Auditorium
|
||||||
import ru.sweetbread.unn.ui.composes.Schedule
|
import ru.sweetbread.unn.ui.Building
|
||||||
|
import ru.sweetbread.unn.ui.Discipline
|
||||||
|
import ru.sweetbread.unn.ui.KindOfWork
|
||||||
|
import ru.sweetbread.unn.ui.Lecturer
|
||||||
|
import ru.sweetbread.unn.ui.LecturerRank
|
||||||
|
import ru.sweetbread.unn.ui.ScheduleUnit
|
||||||
|
import ru.sweetbread.unn.ui.auth
|
||||||
|
import ru.sweetbread.unn.ui.getSchedule
|
||||||
import ru.sweetbread.unn.ui.theme.UNNTheme
|
import ru.sweetbread.unn.ui.theme.UNNTheme
|
||||||
|
import splitties.activities.start
|
||||||
|
import splitties.preferences.Preferences
|
||||||
import splitties.toast.toast
|
import splitties.toast.toast
|
||||||
import java.io.File
|
import java.time.DayOfWeek
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import io.ktor.client.plugins.logging.*
|
||||||
|
import ru.sweetbread.unn.ui.composes.Schedule
|
||||||
|
import ru.sweetbread.unn.ui.composes.ScheduleDay
|
||||||
|
|
||||||
|
object LoginData : Preferences("loginData") {
|
||||||
|
var login by stringPref("login", "")
|
||||||
|
var password by stringPref("password", "")
|
||||||
|
}
|
||||||
|
|
||||||
val client = HttpClient {
|
val client = HttpClient {
|
||||||
install(HttpCache)
|
install(HttpCache)
|
||||||
@ -60,50 +106,46 @@ val client = HttpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val cacheDir = File("/data/data/ru.sweetbread.unn/files/cache")
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Log.d("mkdir", cacheDir.mkdir().toString())
|
|
||||||
|
|
||||||
|
if (LoginData.login.isEmpty() or LoginData.password.isEmpty()) start<LoginActivity>()
|
||||||
|
runBlocking {
|
||||||
|
if (!auth()) start<LoginActivity>()
|
||||||
|
}
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
UNNTheme {
|
UNNTheme {
|
||||||
|
// A surface container using the 'background' color from the theme
|
||||||
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
|
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
var route by remember { mutableStateOf("portal/blogposts") }
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
NavigationBar {
|
NavigationBar {
|
||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
onClick = {
|
onClick = { toast("Not implemented") },
|
||||||
route = "portal/blogposts"
|
|
||||||
navController.navigate(route)
|
|
||||||
},
|
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Filled.Home,
|
Icons.Filled.Home,
|
||||||
contentDescription = "Home"
|
contentDescription = "Home"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
selected = route.startsWith("portal/")
|
selected = navController.currentDestination?.route?.startsWith("home") ?: false
|
||||||
)
|
)
|
||||||
|
|
||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
onClick = {
|
onClick = { navController.navigate("schedule/student/me/today")
|
||||||
route = "journal/schedule"
|
Log.d("route", navController.currentDestination?.route.toString())},
|
||||||
navController.navigate(route)
|
|
||||||
},
|
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Filled.DateRange,
|
Icons.Filled.DateRange,
|
||||||
contentDescription = "Schedule"
|
contentDescription = "Schedule"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
selected = route.startsWith("journal/")
|
selected = navController.currentDestination?.route?.startsWith("schedule") ?: false
|
||||||
)
|
)
|
||||||
|
|
||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
onClick = { toast("Not implemented") },
|
onClick = { toast("Not implemented") },
|
||||||
icon = {
|
icon = {
|
||||||
@ -116,13 +158,19 @@ class MainActivity : ComponentActivity() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
) {innerPadding ->
|
) {innerPadding ->
|
||||||
Box(Modifier.padding(innerPadding)) {
|
Box(Modifier.padding(innerPadding)) {
|
||||||
NavHost(navController, startDestination = "portal/blogposts") {
|
NavHost(navController, startDestination = "home/blogposts") {
|
||||||
composable("portal/blogposts") {
|
composable("home/blogposts") {
|
||||||
Blogposts()
|
Text("Not implemented")
|
||||||
}
|
}
|
||||||
composable("journal/schedule") {
|
composable("schedule/{type}/{who}/{when}",
|
||||||
|
arguments = listOf(
|
||||||
|
navArgument("type") { type = NavType.StringType },
|
||||||
|
navArgument("who") { type = NavType.StringType },
|
||||||
|
navArgument("when") { type = NavType.StringType },)
|
||||||
|
) {
|
||||||
Schedule()
|
Schedule()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
170
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#3DDC84"
|
||||||
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9,0L9,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,0L19,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,0L29,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,0L39,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,0L49,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,0L59,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,0L69,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,0L79,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M89,0L89,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M99,0L99,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,9L108,9"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,19L108,19"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,29L108,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,39L108,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,49L108,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,59L108,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,69L108,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,79L108,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,89L108,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,99L108,99"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,29L89,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,39L89,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,49L89,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,59L89,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,69L89,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,79L89,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,19L29,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,19L39,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,19L49,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,19L59,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,19L69,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,19L79,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
</vector>
|
30
app/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="85.84757"
|
||||||
|
android:endY="92.4963"
|
||||||
|
android:startX="42.9492"
|
||||||
|
android:startY="49.59793"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
</vector>
|
BIN
app/src/main/res/drawable/unn_logo.png
Normal file
After Width: | Height: | Size: 76 KiB |
@ -2,5 +2,4 @@
|
|||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 790 B After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 878 B After Width: | Height: | Size: 942 B |
Before Width: | Height: | Size: 534 B After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.7 KiB |
@ -3,11 +3,4 @@
|
|||||||
<string name="prompt_password">Пароль</string>
|
<string name="prompt_password">Пароль</string>
|
||||||
<string name="prompt_login">Логин</string>
|
<string name="prompt_login">Логин</string>
|
||||||
<string name="sign_in">Войти</string>
|
<string name="sign_in">Войти</string>
|
||||||
<string name="assistant">Ассистент</string>
|
|
||||||
<string name="lecturer">Преподаватель</string>
|
|
||||||
<string name="slecturer">Старший Преподаватель</string>
|
|
||||||
<string name="aprofessor">Доцент</string>
|
|
||||||
<string name="auditorium">Аудитория</string>
|
|
||||||
<string name="building">Здание</string>
|
|
||||||
<string name="floor">Этаж</string>
|
|
||||||
</resources>
|
</resources>
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="ic_launcher_background">#1565AA</color>
|
<color name="ic_launcher_background">#FFFFFF</color>
|
||||||
</resources>
|
</resources>
|
@ -5,13 +5,5 @@
|
|||||||
<string name="prompt_login">Login</string>
|
<string name="prompt_login">Login</string>
|
||||||
<string name="prompt_password">Password</string>
|
<string name="prompt_password">Password</string>
|
||||||
<string name="sign_in">Sign in</string>
|
<string name="sign_in">Sign in</string>
|
||||||
<string name="assistant">Assistant</string>
|
|
||||||
<string name="lecturer">Lecturer</string>
|
|
||||||
<string name="slecturer">Senior Lecturer</string>
|
|
||||||
<string name="aprofessor">Assistant professor</string>
|
|
||||||
<string name="auditorium">Auditorium</string>
|
|
||||||
<string name="building">Building</string>
|
|
||||||
<string name="floor">Floor</string>
|
|
||||||
<string name="lorem" translatable="false">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vel iaculis elit. Aliquam varius urna ut nisl rhoncus ullamcorper. Maecenas et nisl at dui mollis maximus nec in libero. Ut eu nulla id felis hendrerit lobortis. Maecenas vel facilisis lectus. Morbi eleifend massa a ante consequat, eu aliquam elit euismod. Aenean quis erat tincidunt, egestas ligula id, convallis tortor. Vivamus volutpat condimentum nisl sed eleifend. Aenean dapibus dolor ut orci lobortis, placerat lobortis tortor pretium. Nam eros lectus, convallis sed ultricies sit amet, lacinia sed sem. In mi odio, porta non malesuada et, cursus a metus. Morbi quis odio sed quam commodo gravida id sit amet dolor. Donec ac iaculis massa. Nulla mauris sapien, auctor consequat est in, tempus accumsan ipsum. Donec semper volutpat nisi. Quisque dignissim tellus ipsum, sed malesuada libero aliquam sed. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nam eleifend pharetra orci eu scelerisque. In hac habitasse platea dictumst. Sed non neque vitae metus porttitor vestibulum ut eget felis. Aliquam venenatis a magna eu mattis. Proin rutrum, sapien id viverra finibus, nisi quam aliquam eros, et dignissim lectus sem sit amet purus. Donec et semper enim, sed pretium lacus. Nullam venenatis ullamcorper maximus. Mauris pellentesque velit non sem sollicitudin molestie. Duis hendrerit consequat enim eget euismod.</string>
|
|
||||||
<!-- <string name="login_failed">"Login failed"</string>-->
|
<!-- <string name="login_failed">"Login failed"</string>-->
|
||||||
</resources>
|
</resources>
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="Theme.UNN" parent="android:Theme.Material.NoActionBar" />
|
<style name="Theme.UNN" parent="android:Theme.Material.Light.NoActionBar" />
|
||||||
</resources>
|
</resources>
|
36
app/src/main/res/xml/data_extraction_rules.xml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Sample data extraction rules file; uncomment and customize as necessary.
|
||||||
|
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||||
|
for details.
|
||||||
|
-->
|
||||||
|
<data-extraction-rules>
|
||||||
|
<cloud-backup>
|
||||||
|
<!--
|
||||||
|
TODO: Use <include> and <exclude> to control what is backed up.
|
||||||
|
The domain can be file, database, sharedpref, external or root.
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
<include domain="file" path="file_to_include"/>
|
||||||
|
<exclude domain="file" path="file_to_exclude"/>
|
||||||
|
<include domain="file" path="include_folder"/>
|
||||||
|
<exclude domain="file" path="include_folder/file_to_exclude"/>
|
||||||
|
<exclude domain="file" path="exclude_folder"/>
|
||||||
|
<include domain="file" path="exclude_folder/file_to_include"/>
|
||||||
|
|
||||||
|
<include domain="sharedpref" path="include_shared_pref1.xml"/>
|
||||||
|
<include domain="database" path="db_name/file_to_include"/>
|
||||||
|
<exclude domain="database" path="db_name/include_folder/file_to_exclude"/>
|
||||||
|
<include domain="external" path="file_to_include"/>
|
||||||
|
<exclude domain="external" path="file_to_exclude"/>
|
||||||
|
<include domain="root" path="file_to_include"/>
|
||||||
|
<exclude domain="root" path="file_to_exclude"/>
|
||||||
|
-->
|
||||||
|
</cloud-backup>
|
||||||
|
<!--
|
||||||
|
<device-transfer>
|
||||||
|
<include .../>
|
||||||
|
<exclude .../>
|
||||||
|
</device-transfer>
|
||||||
|
-->
|
||||||
|
</data-extraction-rules>
|
@ -3,9 +3,3 @@ plugins {
|
|||||||
alias(libs.plugins.androidApplication) apply false
|
alias(libs.plugins.androidApplication) apply false
|
||||||
alias(libs.plugins.jetbrainsKotlinAndroid) apply false
|
alias(libs.plugins.jetbrainsKotlinAndroid) apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
buildscript {
|
|
||||||
dependencies {
|
|
||||||
classpath(libs.secrets.gradle.plugin)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +1,32 @@
|
|||||||
[versions]
|
[versions]
|
||||||
acraHttp = "5.11.3"
|
agp = "8.3.0"
|
||||||
agp = "8.3.1"
|
|
||||||
coilCompose = "2.6.0"
|
|
||||||
compose = "2.5.0"
|
|
||||||
coreSplashscreen = "1.0.1"
|
|
||||||
datastorePreferences = "1.0.0"
|
datastorePreferences = "1.0.0"
|
||||||
desugar_jdk_libs = "2.0.4"
|
|
||||||
kotlin = "1.9.0"
|
kotlin = "1.9.0"
|
||||||
coreKtx = "1.12.0"
|
coreKtx = "1.10.1"
|
||||||
|
junit = "4.13.2"
|
||||||
junitVersion = "1.1.5"
|
junitVersion = "1.1.5"
|
||||||
espressoCore = "3.5.1"
|
espressoCore = "3.5.1"
|
||||||
ktorClientCio = "2.3.9"
|
ktorClientCio = "2.3.9"
|
||||||
ktorClientCore = "2.3.9"
|
ktorClientCore = "2.3.9"
|
||||||
ktorClientLogging = "2.3.9"
|
ktorClientLogging = "2.3.9"
|
||||||
lifecycleRuntimeKtx = "2.7.0"
|
lifecycleRuntimeKtx = "2.6.1"
|
||||||
activityCompose = "1.8.2"
|
activityCompose = "1.7.0"
|
||||||
composeBom = "2024.02.02"
|
composeBom = "2023.08.00"
|
||||||
appcompat = "1.6.1"
|
appcompat = "1.6.1"
|
||||||
material = "1.11.0"
|
material = "1.10.0"
|
||||||
annotation = "1.7.1"
|
annotation = "1.6.0"
|
||||||
constraintlayout = "2.1.4"
|
constraintlayout = "2.1.4"
|
||||||
lifecycleLivedataKtx = "2.7.0"
|
lifecycleLivedataKtx = "2.6.1"
|
||||||
lifecycleViewmodelKtx = "2.7.0"
|
lifecycleViewmodelKtx = "2.6.1"
|
||||||
activity = "1.8.2"
|
activity = "1.8.0"
|
||||||
navigationCompose = "2.7.7"
|
navigationCompose = "2.7.7"
|
||||||
richeditorCompose = "1.0.0-rc01"
|
|
||||||
secretsGradlePlugin = "2.0.1"
|
|
||||||
splittiesFunPackAndroidBaseWithViewsDsl = "3.0.0"
|
splittiesFunPackAndroidBaseWithViewsDsl = "3.0.0"
|
||||||
kefirbb = "1.5"
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
acra-http = { module = "ch.acra:acra-http", version.ref = "acraHttp" }
|
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" }
|
|
||||||
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
|
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
|
||||||
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
|
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
|
||||||
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" }
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
compose = { module = "com.kizitonwose.calendar:compose", version.ref = "compose" }
|
|
||||||
desugar_jdk_libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar_jdk_libs" }
|
|
||||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||||
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
||||||
@ -60,10 +49,7 @@ androidx-constraintlayout = { group = "androidx.constraintlayout", name = "const
|
|||||||
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
|
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
|
||||||
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
|
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||||
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
||||||
richeditor-compose = { module = "com.mohamedrejeb.richeditor:richeditor-compose", version.ref = "richeditorCompose" }
|
splitties-fun-pack-android-base-with-views-dsl = { module = "com.louiscad.splitties:splitties-fun-pack-android-base-with-views-dsl", version.ref = "splittiesFunPackAndroidBaseWithViewsDsl" }
|
||||||
secrets-gradle-plugin = { module = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin", version.ref = "secretsGradlePlugin" }
|
|
||||||
splitties-funpack-android-base-with-views-dsl = { module = "com.louiscad.splitties:splitties-fun-pack-android-base-with-views-dsl", version.ref = "splittiesFunPackAndroidBaseWithViewsDsl" }
|
|
||||||
kefirbb = { group = "org.kefirsf", name = "kefirbb", version.ref = "kefirbb" }
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||||
|