lab5
This commit is contained in:
parent
71f82033ec
commit
e4a08474a5
@ -1,4 +1,3 @@
|
||||
package ru.ulstu.is.pmu.api
|
||||
package ru.ulstu.`is`.pmu.api
|
||||
|
||||
class ApiStatus {
|
||||
}
|
||||
enum class ApiStatus { LOADING, ERROR, DONE }
|
@ -21,9 +21,16 @@ import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
import ru.ulstu.`is`.pmu.api.model.UserRemote
|
||||
import ru.ulstu.`is`.pmu.api.model.TaskRemote
|
||||
import ru.ulstu.`is`.pmu.api.report.ReportRemote
|
||||
|
||||
|
||||
interface MyServerService {
|
||||
@GET("report")
|
||||
suspend fun getReportInfo(
|
||||
@Query("fromDate") fromDate: String,
|
||||
@Query("toDate") toDate: String
|
||||
): List<ReportRemote>
|
||||
|
||||
@GET("users")
|
||||
suspend fun getUsers(): List<UserRemote>
|
||||
|
||||
|
@ -9,8 +9,8 @@ data class TaskRemote(
|
||||
val name: String = "",
|
||||
val description: String = "",
|
||||
val endDate: String = "",
|
||||
val favorite: Boolean,
|
||||
val userId: Int,
|
||||
val favorite: Boolean = false, // Значение по умолчанию
|
||||
val userId: Int = 1, // Значение по умолчанию
|
||||
)
|
||||
|
||||
fun TaskRemote.toTask(): Task = Task(
|
||||
@ -18,7 +18,7 @@ fun TaskRemote.toTask(): Task = Task(
|
||||
name,
|
||||
description,
|
||||
endDate,
|
||||
favorite = false,
|
||||
favorite,
|
||||
userId
|
||||
)
|
||||
|
||||
@ -27,6 +27,6 @@ fun Task.toTaskRemote(): TaskRemote = TaskRemote(
|
||||
name,
|
||||
description,
|
||||
endDate,
|
||||
favorite = false,
|
||||
favorite,
|
||||
userId = 1
|
||||
)
|
@ -1,4 +1,11 @@
|
||||
package ru.ulstu.is.pmu.api.report
|
||||
package ru.ulstu.`is`.pmu.api.report
|
||||
|
||||
class ReportRemote {
|
||||
}
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ReportRemote(
|
||||
val id: Int = 0,
|
||||
val name: String = "",
|
||||
val description: String = "",
|
||||
val endDate: String = ""
|
||||
)
|
@ -10,12 +10,16 @@ import ru.ulstu.`is`.pmu.api.MyServerService
|
||||
import ru.ulstu.`is`.pmu.api.user.RestUserRepository
|
||||
import ru.ulstu.`is`.pmu.api.model.toTask
|
||||
import ru.ulstu.`is`.pmu.api.model.toTaskRemote
|
||||
import ru.ulstu.`is`.pmu.api.report.ReportRemote
|
||||
import ru.ulstu.`is`.pmu.common.AppContainer
|
||||
import ru.ulstu.`is`.pmu.common.TaskRepository
|
||||
import ru.ulstu.`is`.pmu.database.AppDatabase
|
||||
import ru.ulstu.`is`.pmu.database.remotekeys.repository.OfflineRemoteKeyRepository
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
import ru.ulstu.`is`.pmu.database.task.repository.OfflineTaskRepository
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class RestTaskRepository(
|
||||
private val service: MyServerService,
|
||||
@ -46,6 +50,50 @@ class RestTaskRepository(
|
||||
).flow
|
||||
}
|
||||
|
||||
override fun getAllFavoriteTasks(): Flow<PagingData<Task>> {
|
||||
Log.d(RestTaskRepository::class.simpleName, "Get tasks")
|
||||
|
||||
val pagingSourceFactory = { dbTaskRepository.getAllTasksFavoritePagingSource() }
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
return Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
remoteMediator = TaskRemoteMediator(
|
||||
service,
|
||||
dbTaskRepository,
|
||||
dbRemoteKeyRepository,
|
||||
userRestRepository,
|
||||
database,
|
||||
),
|
||||
pagingSourceFactory = pagingSourceFactory
|
||||
).flow
|
||||
}
|
||||
|
||||
override fun getAllDateTasks(): Flow<PagingData<Task>> {
|
||||
Log.d(RestTaskRepository::class.simpleName, "Get tasks")
|
||||
|
||||
val pagingSourceFactory = { dbTaskRepository.getAllTasksDatePagingSource() }
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
return Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
remoteMediator = TaskRemoteMediator(
|
||||
service,
|
||||
dbTaskRepository,
|
||||
dbRemoteKeyRepository,
|
||||
userRestRepository,
|
||||
database,
|
||||
),
|
||||
pagingSourceFactory = pagingSourceFactory
|
||||
).flow
|
||||
}
|
||||
|
||||
override suspend fun getTask(uid: Int): Task =
|
||||
service.getTask(uid).toTask()
|
||||
|
||||
@ -60,4 +108,19 @@ class RestTaskRepository(
|
||||
override suspend fun deleteTask(task: Task) {
|
||||
service.deleteTask(task.uid).toTask()
|
||||
}
|
||||
|
||||
override suspend fun favoriteTask(task: Task) {
|
||||
task.favorite = true
|
||||
service.updateTask(task.uid, task.toTaskRemote()).toTask()
|
||||
}
|
||||
|
||||
override suspend fun deletefavoriteTask(task: Task) {
|
||||
task.favorite = false
|
||||
service.updateTask(task.uid, task.toTaskRemote()).toTask()
|
||||
}
|
||||
|
||||
suspend fun getReport(fromDate: String, toDate: String):List<ReportRemote>
|
||||
{
|
||||
return service.getReportInfo(fromDate,toDate)
|
||||
}
|
||||
}
|
@ -6,8 +6,11 @@ import androidx.lifecycle.viewmodel.CreationExtras
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import ru.ulstu.`is`.pmu.TaskApplication
|
||||
import ru.ulstu.`is`.pmu.ui.ReportViewModel
|
||||
import ru.ulstu.`is`.pmu.ui.task.edit.UserDropDownViewModel
|
||||
import ru.ulstu.`is`.pmu.ui.task.edit.TaskEditViewModel
|
||||
import ru.ulstu.`is`.pmu.ui.task.list.FavoriteTaskList
|
||||
import ru.ulstu.`is`.pmu.ui.task.list.FavoriteTaskListViewModel
|
||||
import ru.ulstu.`is`.pmu.ui.task.list.TaskListViewModel
|
||||
|
||||
object AppViewModelProvider {
|
||||
@ -24,6 +27,14 @@ object AppViewModelProvider {
|
||||
initializer {
|
||||
UserDropDownViewModel(taskApplication().container.userRestRepository)
|
||||
}
|
||||
initializer {
|
||||
FavoriteTaskListViewModel(taskApplication().container.taskRestRepository)
|
||||
}
|
||||
initializer {
|
||||
ReportViewModel(
|
||||
taskApplication().container.taskRestRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,12 @@ import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
|
||||
interface TaskRepository {
|
||||
fun getAllTasks(): Flow<PagingData<Task>>
|
||||
fun getAllFavoriteTasks(): Flow<PagingData<Task>>
|
||||
fun getAllDateTasks(): Flow<PagingData<Task>>
|
||||
suspend fun getTask(uid: Int): Task
|
||||
suspend fun insertTask(task: Task)
|
||||
suspend fun updateTask(task: Task)
|
||||
suspend fun deleteTask(task: Task)
|
||||
suspend fun favoriteTask(task: Task)
|
||||
suspend fun deletefavoriteTask(task: Task)
|
||||
}
|
@ -5,9 +5,11 @@ import androidx.room.PrimaryKey
|
||||
import androidx.room.TypeConverter
|
||||
import androidx.room.TypeConverters
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
import ru.ulstu.`is`.pmu.database.task.model.User
|
||||
|
||||
enum class RemoteKeyType(private val type: String) {
|
||||
STUDENT(Task::class.simpleName ?: "Task");
|
||||
STUDENT(Task::class.simpleName ?: "Task"),
|
||||
USER(User::class.simpleName ?: "User");
|
||||
|
||||
@TypeConverter
|
||||
fun toRemoteKeyType(value: String) = RemoteKeyType.values().first { it.type == value }
|
||||
|
@ -14,6 +14,12 @@ interface TaskDao {
|
||||
@Query("select * from tasks order by name collate nocase asc")
|
||||
fun getAll(): PagingSource<Int, Task>
|
||||
|
||||
@Query("SELECT * FROM tasks WHERE favorite = 1")
|
||||
fun getFavoriteTasks(): PagingSource<Int, Task>
|
||||
|
||||
@Query("SELECT * FROM tasks ORDER BY DATE(SUBSTR(endDate, 7, 4) || '-' || SUBSTR(endDate, 4, 2) || '-' || SUBSTR(endDate, 1, 2)) ASC")
|
||||
fun getTasksSortedByDate(): PagingSource<Int, Task>
|
||||
|
||||
@Query("select * from tasks where tasks.uid = :uid")
|
||||
fun getByUid(uid: Int): Flow<Task>
|
||||
|
||||
@ -26,6 +32,9 @@ interface TaskDao {
|
||||
@Delete
|
||||
suspend fun delete(task: Task)
|
||||
|
||||
@Query("UPDATE tasks SET favorite = :favorite WHERE uid = :taskId")
|
||||
suspend fun updateFavorite(taskId: Int, favorite: Boolean)
|
||||
|
||||
@Query("DELETE FROM tasks")
|
||||
suspend fun deleteAll()
|
||||
}
|
@ -1,23 +1,27 @@
|
||||
package ru.ulstu.`is`.pmu.database.task.dao
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
import ru.ulstu.`is`.pmu.database.task.model.User
|
||||
|
||||
@Dao
|
||||
interface UserDao {
|
||||
@Query("select * from users order by login collate nocase asc")
|
||||
suspend fun getAll(): List<User>
|
||||
|
||||
@Insert
|
||||
suspend fun insert(user: User)
|
||||
suspend fun insert(vararg user: User)
|
||||
|
||||
@Update
|
||||
suspend fun update(user: User)
|
||||
|
||||
@Delete
|
||||
suspend fun delete(user: User)
|
||||
|
||||
@Query("DELETE FROM users")
|
||||
suspend fun deleteAll()
|
||||
}
|
@ -39,7 +39,7 @@ data class Task(
|
||||
endDate: String,
|
||||
favorite: Boolean,
|
||||
user: User,
|
||||
) : this(0, name, description, endDate, favorite, user.uid)
|
||||
) : this(0, name, description, endDate, favorite, 1)
|
||||
|
||||
|
||||
companion object {
|
||||
|
@ -20,6 +20,22 @@ class OfflineTaskRepository(private val taskDao: TaskDao) : TaskRepository {
|
||||
pagingSourceFactory = taskDao::getAll
|
||||
).flow
|
||||
|
||||
override fun getAllFavoriteTasks(): Flow<PagingData<Task>> = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = taskDao::getFavoriteTasks
|
||||
).flow
|
||||
|
||||
override fun getAllDateTasks(): Flow<PagingData<Task>> = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = AppContainer.LIMIT,
|
||||
enablePlaceholders = false
|
||||
),
|
||||
pagingSourceFactory = taskDao::getTasksSortedByDate
|
||||
).flow
|
||||
|
||||
override suspend fun getTask(uid: Int): Task = taskDao.getByUid(uid).first()
|
||||
|
||||
override suspend fun insertTask(task: Task) = taskDao.insert(task)
|
||||
@ -27,12 +43,21 @@ class OfflineTaskRepository(private val taskDao: TaskDao) : TaskRepository {
|
||||
override suspend fun updateTask(task: Task) = taskDao.update(task)
|
||||
|
||||
override suspend fun deleteTask(task: Task) = taskDao.delete(task)
|
||||
|
||||
override suspend fun favoriteTask(task: Task) {
|
||||
TODO("Not yet implemented")
|
||||
taskDao.updateFavorite(task.uid, !task.favorite)
|
||||
}
|
||||
|
||||
override suspend fun deletefavoriteTask(task: Task) {
|
||||
taskDao.updateFavorite(task.uid, !task.favorite)
|
||||
}
|
||||
|
||||
fun getAllTasksPagingSource(): PagingSource<Int, Task> = taskDao.getAll()
|
||||
|
||||
fun getAllTasksFavoritePagingSource(): PagingSource<Int, Task> = taskDao.getFavoriteTasks()
|
||||
|
||||
fun getAllTasksDatePagingSource(): PagingSource<Int, Task> = taskDao.getTasksSortedByDate()
|
||||
|
||||
suspend fun insertTasks(tasks: List<Task>) =
|
||||
taskDao.insert(*tasks.toTypedArray())
|
||||
|
||||
|
@ -1,11 +1,23 @@
|
||||
package ru.ulstu.`is`.pmu.database.task.repository
|
||||
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingSource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import ru.ulstu.`is`.pmu.common.AppContainer
|
||||
import ru.ulstu.`is`.pmu.common.UserRepository
|
||||
import ru.ulstu.`is`.pmu.database.task.dao.UserDao
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
import ru.ulstu.`is`.pmu.database.task.model.User
|
||||
|
||||
class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
|
||||
override suspend fun getAllUsers(): List<User> = userDao.getAll()
|
||||
|
||||
suspend fun insertUsers(users: List<User>) =
|
||||
userDao.insert(*users.toTypedArray())
|
||||
|
||||
suspend fun createUser(user: User) = userDao.insert(user)
|
||||
suspend fun updateUser(user: User) = userDao.update(user)
|
||||
suspend fun clearUsers() = userDao.deleteAll()
|
||||
}
|
@ -1,4 +1,362 @@
|
||||
package ru.ulstu.is.pmu.ui
|
||||
package ru.ulstu.`is`.pmu.ui
|
||||
|
||||
class ReportPage {
|
||||
import android.content.ContentResolver
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.pdf.PdfDocument
|
||||
import android.net.Uri
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.widget.CalendarView
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.DatePicker
|
||||
import androidx.compose.material3.DatePickerState
|
||||
import androidx.compose.material3.DisplayMode
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.rememberDatePickerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import ru.ulstu.`is`.pmu.R
|
||||
import ru.ulstu.`is`.pmu.api.report.ReportRemote
|
||||
import ru.ulstu.`is`.pmu.common.AppViewModelProvider
|
||||
import ru.ulstu.`is`.pmu.ui.ReportViewModel
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ReportPage(navController: NavController?, viewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory)) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
var showStartDatePicker by remember { mutableStateOf(false) }
|
||||
var showEndDatePicker by remember { mutableStateOf(false) }
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Button(
|
||||
onClick = { showStartDatePicker = true },
|
||||
modifier = Modifier.width(350.dp)
|
||||
) {
|
||||
Text("Начальная дата")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (showStartDatePicker) {
|
||||
DatePicker(
|
||||
onDateSelected = { selectedDate ->
|
||||
viewModel.onUpdate(viewModel.reportPageUiState.reportDetails.copy(startDate = selectedDate))
|
||||
showStartDatePicker = false
|
||||
},
|
||||
onDismissRequest = { showStartDatePicker = false }
|
||||
)
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = { showEndDatePicker = true },
|
||||
modifier = Modifier.width(350.dp)
|
||||
) {
|
||||
Text("Конечная дата")
|
||||
}
|
||||
|
||||
if (showEndDatePicker) {
|
||||
DatePicker(
|
||||
onDateSelected = { selectedDate ->
|
||||
viewModel.onUpdate(viewModel.reportPageUiState.reportDetails.copy(endDate = selectedDate))
|
||||
showEndDatePicker = false
|
||||
if (viewModel.reportPageUiState.reportDetails.startDate != null) {
|
||||
coroutineScope.launch {
|
||||
viewModel.getReport()
|
||||
createPdfFile(context, "Отчет.pdf", viewModel.reportResultPageUiState.resReport)
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissRequest = { showEndDatePicker = false }
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
Text(
|
||||
text = "Результат",
|
||||
style = MaterialTheme.typography.headlineLarge
|
||||
)
|
||||
|
||||
ReportTable(reportData = viewModel.reportResultPageUiState.resReport)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Composable
|
||||
fun ReportTable(reportData: List<ReportRemote>) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
reportData.forEach { report ->
|
||||
ReportCard(report)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ReportCard(report: ReportRemote) {
|
||||
val (taskId, taskName, taskDescription, taskEndDate) = report
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.fillMaxWidth(),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) // Исправлено здесь
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text("ID: ${taskId}", style = MaterialTheme.typography.bodyMedium)
|
||||
Text("Название: $taskName", style = MaterialTheme.typography.bodyMedium)
|
||||
Text("Описание: $taskDescription", style = MaterialTheme.typography.bodyMedium)
|
||||
Text("Дата завершения: $taskEndDate", style = MaterialTheme.typography.bodyMedium)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CustomCalendarView(onDateSelected: (Date) -> Unit) {
|
||||
AndroidView(
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
factory = { context ->
|
||||
val calendarView = CalendarView(context)
|
||||
|
||||
// Настройки CalendarView
|
||||
val calendar = Calendar.getInstance()
|
||||
|
||||
calendarView.setOnDateChangeListener { _, year, month, dayOfMonth ->
|
||||
calendar.set(Calendar.YEAR, year)
|
||||
calendar.set(Calendar.MONTH, month)
|
||||
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth)
|
||||
onDateSelected(calendar.time)
|
||||
}
|
||||
|
||||
calendarView
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DatePicker(onDateSelected: (Date) -> Unit, onDismissRequest: () -> Unit) {
|
||||
val selDate = remember { mutableStateOf(Date()) }
|
||||
|
||||
//todo - add strings to resource after POC
|
||||
Dialog(onDismissRequest = { onDismissRequest() }, properties = DialogProperties()) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.background(
|
||||
color = Color.White
|
||||
)
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.defaultMinSize(minHeight = 72.dp)
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Выберите дату"
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.size(24.dp))
|
||||
|
||||
Text(
|
||||
text = SimpleDateFormat("MMM d, yyyy", Locale.getDefault()).format(selDate.value)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
}
|
||||
|
||||
CustomCalendarView(onDateSelected = {
|
||||
selDate.value = it
|
||||
})
|
||||
|
||||
Spacer(modifier = Modifier.size(8.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.align(Alignment.End)
|
||||
.padding(bottom = 16.dp, end = 16.dp)
|
||||
.background(
|
||||
color = Color.White,
|
||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
|
||||
)
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onDismissRequest
|
||||
) {
|
||||
//TODO - hardcode string
|
||||
Text(
|
||||
text = "Отмена"
|
||||
)
|
||||
}
|
||||
|
||||
TextButton(
|
||||
onClick = {
|
||||
onDateSelected(selDate.value)
|
||||
onDismissRequest()
|
||||
}
|
||||
) {
|
||||
//TODO - hardcode string
|
||||
Text(
|
||||
text = "Подтвердить"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun createPdfFile(context: Context, fileName: String, reportData: List<ReportRemote>) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
|
||||
put(MediaStore.MediaColumns.MIME_TYPE, "application/pdf")
|
||||
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOCUMENTS)
|
||||
}
|
||||
|
||||
val contentResolver: ContentResolver = context.contentResolver
|
||||
val uri: Uri? = contentResolver.insert(MediaStore.Files.getContentUri("external"), contentValues)
|
||||
|
||||
uri?.let {
|
||||
try {
|
||||
contentResolver.openOutputStream(uri)?.use { outputStream ->
|
||||
createPdfContent(outputStream, reportData)
|
||||
}
|
||||
|
||||
context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri))
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPdfContent(outputStream: OutputStream, reportData: List<ReportRemote>) {
|
||||
val pdfDocument = PdfDocument()
|
||||
|
||||
val pageInfo = PdfDocument.PageInfo.Builder(595, 842, 1).create()
|
||||
val page = pdfDocument.startPage(pageInfo)
|
||||
val canvas = page.canvas
|
||||
|
||||
val paint = Paint()
|
||||
paint.color = android.graphics.Color.BLACK
|
||||
paint.textSize = 24f
|
||||
|
||||
// Отображаем заголовок
|
||||
val title = "Отчет"
|
||||
val xTitle = (pageInfo.pageWidth - paint.measureText(title)) / 2
|
||||
val yTitle = 40f
|
||||
canvas.drawText(title, xTitle, yTitle, paint)
|
||||
|
||||
// Определение структуры таблицы
|
||||
val tableWidth = pageInfo.pageWidth - 80f
|
||||
val columnCount = 4
|
||||
val columnWidth = tableWidth / columnCount
|
||||
val rowHeight = 40f
|
||||
|
||||
// Отображаем заголовки столбцов
|
||||
val columnHeaderPaint = Paint()
|
||||
columnHeaderPaint.color = android.graphics.Color.BLACK
|
||||
columnHeaderPaint.textSize = 18f
|
||||
val columnHeaderTitles = listOf("ID", "Название", "Описание", "Дата окончания")
|
||||
for (i in 0 until columnCount) {
|
||||
val x = 40f + i * columnWidth
|
||||
val y = yTitle + 80f
|
||||
canvas.drawText(columnHeaderTitles[i], x, y, columnHeaderPaint)
|
||||
}
|
||||
|
||||
// Отображаем данные в таблице
|
||||
val rowDataPaint = Paint()
|
||||
rowDataPaint.color = android.graphics.Color.BLACK
|
||||
rowDataPaint.textSize = 18f
|
||||
for ((index, report) in reportData.withIndex()) {
|
||||
val x = 40f
|
||||
val y = yTitle + 120f + index * rowHeight
|
||||
|
||||
// Отображаем данные каждого столбца
|
||||
canvas.drawText(report.id.toString(), x, y, rowDataPaint)
|
||||
canvas.drawText(report.name, x + columnWidth, y, rowDataPaint)
|
||||
canvas.drawText(report.description, x + 2 * columnWidth, y, rowDataPaint)
|
||||
canvas.drawText(report.endDate, x + 3 * columnWidth, y, rowDataPaint)
|
||||
}
|
||||
|
||||
pdfDocument.finishPage(page)
|
||||
|
||||
pdfDocument.writeTo(outputStream)
|
||||
pdfDocument.close()
|
||||
}
|
||||
|
||||
private fun drawCell(canvas: Canvas, paint: Paint, text: String, x: Float, y: Float, width: Int) {
|
||||
canvas.drawText(text, x + (width - paint.measureText(text)) / 2, y + paint.textSize, paint)
|
||||
}
|
@ -9,8 +9,10 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.ulstu.`is`.pmu.api.model.TaskRemote
|
||||
import ru.ulstu.`is`.pmu.api.model.toTask
|
||||
import ru.ulstu.`is`.pmu.api.report.ReportRemote
|
||||
import ru.ulstu.`is`.pmu.api.task.RestTaskRepository
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
@ -29,8 +29,10 @@ import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import ru.ulstu.`is`.pmu.R
|
||||
import ru.ulstu.`is`.pmu.ui.ReportPage
|
||||
import ru.ulstu.`is`.pmu.ui.about.About
|
||||
import ru.ulstu.`is`.pmu.ui.task.edit.TaskEdit
|
||||
import ru.ulstu.`is`.pmu.ui.task.list.FavoriteTaskList
|
||||
import ru.ulstu.`is`.pmu.ui.task.list.TaskList
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@ -109,6 +111,8 @@ fun Navhost(
|
||||
) {
|
||||
TaskEdit(navController)
|
||||
}
|
||||
composable(Screen.TaskFavoriteList.route) { FavoriteTaskList(navController) }
|
||||
composable(Screen.Report.route) { ReportPage(navController = navController) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.List
|
||||
import androidx.compose.material.icons.filled.Send
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import ru.ulstu.`is`.pmu.R
|
||||
|
||||
@ -20,6 +21,12 @@ enum class Screen(
|
||||
About(
|
||||
"about", R.string.about_title, Icons.Filled.Info
|
||||
),
|
||||
TaskFavoriteList(
|
||||
"task-favorite", R.string.task_favorite_view_title
|
||||
),
|
||||
Report(
|
||||
"report", R.string.report, Icons.Filled.Send
|
||||
),
|
||||
TaskEdit(
|
||||
"task-edit/{id}", R.string.task_view_title, showInBottomBar = false
|
||||
);
|
||||
@ -27,7 +34,9 @@ enum class Screen(
|
||||
companion object {
|
||||
val bottomBarItems = listOf(
|
||||
TaskList,
|
||||
TaskFavoriteList,
|
||||
About,
|
||||
Report
|
||||
)
|
||||
|
||||
fun getItem(route: String): Screen? {
|
||||
|
@ -1,11 +1,19 @@
|
||||
package ru.ulstu.`is`.pmu.ui.task.edit
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.widget.CalendarView
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
@ -16,6 +24,7 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
@ -23,12 +32,16 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import kotlinx.coroutines.launch
|
||||
@ -37,6 +50,10 @@ import ru.ulstu.`is`.pmu.database.task.model.User
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
import ru.ulstu.`is`.pmu.common.AppViewModelProvider
|
||||
import ru.ulstu.`is`.pmu.ui.theme.PmudemoTheme
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
@Composable
|
||||
fun TaskEdit(
|
||||
@ -44,17 +61,14 @@ fun TaskEdit(
|
||||
viewModel: TaskEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||
userViewModel: UserDropDownViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
userViewModel.setCurrentUser(viewModel.taskUiState.taskDetails.userId)
|
||||
TaskEdit(
|
||||
taskUiState = viewModel.taskUiState,
|
||||
userUiState = userViewModel.userUiState,
|
||||
usersListUiState = userViewModel.usersListUiState,
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
viewModel.saveTask()
|
||||
navController.popBackStack()
|
||||
}
|
||||
},
|
||||
onUpdate = viewModel::updateUiState,
|
||||
onUserUpdate = userViewModel::updateUiState
|
||||
@ -121,6 +135,7 @@ private fun TaskEdit(
|
||||
onUpdate: (TaskDetails) -> Unit,
|
||||
onUserUpdate: (User) -> Unit
|
||||
) {
|
||||
var showInvalidDateDialog by remember { mutableStateOf(false) }
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
@ -140,48 +155,166 @@ private fun TaskEdit(
|
||||
label = { Text(stringResource(id = R.string.task_lastname)) },
|
||||
singleLine = true
|
||||
)
|
||||
UserDropDown(
|
||||
userUiState = userUiState,
|
||||
usersListUiState = usersListUiState,
|
||||
onUserUpdate = {
|
||||
onUpdate(taskUiState.taskDetails.copy(userId = it.uid))
|
||||
onUserUpdate(it)
|
||||
}
|
||||
)
|
||||
var showDatePicker by remember { mutableStateOf(false) }
|
||||
if (showDatePicker) {
|
||||
DatePicker(
|
||||
onDateSelected = { selectedDate ->
|
||||
onUpdate(taskUiState.taskDetails.copy(endDate = SimpleDateFormat("dd.MM.yyyy").format(selectedDate)))
|
||||
showDatePicker = false
|
||||
},
|
||||
onDismissRequest = {
|
||||
showDatePicker = false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = { showDatePicker = true },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Выбрать дату окончания")
|
||||
}
|
||||
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = taskUiState.taskDetails.endDate,
|
||||
onValueChange = { onUpdate(taskUiState.taskDetails.copy(endDate = it)) },
|
||||
label = { Text(stringResource(id = R.string.task_phone)) },
|
||||
singleLine = true
|
||||
singleLine = true ,
|
||||
enabled = false
|
||||
)
|
||||
Button(
|
||||
onClick = onClick,
|
||||
onClick = {
|
||||
if (!isValidDate(taskUiState.taskDetails.endDate)) {
|
||||
showInvalidDateDialog = true
|
||||
} else {
|
||||
onClick()
|
||||
}
|
||||
},
|
||||
enabled = taskUiState.isEntryValid,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(text = stringResource(R.string.task_save_button))
|
||||
}
|
||||
}
|
||||
|
||||
if (showInvalidDateDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showInvalidDateDialog = false },
|
||||
title = { Text("Неверный формат даты") },
|
||||
text = { Text("Введите дату по шаблону: 01.12.2023") },
|
||||
confirmButton = {
|
||||
Button(onClick = { showInvalidDateDialog = false }) {
|
||||
Text("Подтвердить")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun isValidDate(date: String): Boolean {
|
||||
val regex = Regex("""^\d{2}\.\d{2}\.\d{4}$""")
|
||||
return regex.matches(date)
|
||||
}
|
||||
|
||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun TaskEditPreview() {
|
||||
PmudemoTheme {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background
|
||||
fun CustomCalendarView(onDateSelected: (Date) -> Unit) {
|
||||
AndroidView(
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
factory = { context ->
|
||||
val calendarView = CalendarView(context)
|
||||
|
||||
// Настройки CalendarView
|
||||
val calendar = Calendar.getInstance()
|
||||
|
||||
// Устанавливаем минимальную дату выбора на сегодняшний день
|
||||
calendarView.minDate = calendar.timeInMillis
|
||||
|
||||
calendarView.setOnDateChangeListener { _, year, month, dayOfMonth ->
|
||||
calendar.set(Calendar.YEAR, year)
|
||||
calendar.set(Calendar.MONTH, month)
|
||||
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth)
|
||||
onDateSelected(calendar.time)
|
||||
}
|
||||
|
||||
calendarView
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun DatePicker(onDateSelected: (Date) -> Unit, onDismissRequest: () -> Unit) {
|
||||
val selDate = remember { mutableStateOf(Date()) }
|
||||
|
||||
//todo - add strings to resource after POC
|
||||
Dialog(onDismissRequest = { onDismissRequest() }, properties = DialogProperties()) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.background(
|
||||
color = Color.White
|
||||
)
|
||||
) {
|
||||
TaskEdit(
|
||||
taskUiState = Task.getTask().toUiState(true),
|
||||
userUiState = User.DEMO_User.toUiState(),
|
||||
usersListUiState = UsersListUiState(listOf()),
|
||||
onClick = {},
|
||||
onUpdate = {},
|
||||
onUserUpdate = {}
|
||||
)
|
||||
Column(
|
||||
Modifier
|
||||
.defaultMinSize(minHeight = 72.dp)
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Выберите дату"
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.size(24.dp))
|
||||
|
||||
Text(
|
||||
text = SimpleDateFormat("MMM d, yyyy", Locale.getDefault()).format(selDate.value)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
}
|
||||
|
||||
CustomCalendarView(onDateSelected = {
|
||||
selDate.value = it
|
||||
})
|
||||
|
||||
Spacer(modifier = Modifier.size(8.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.align(Alignment.End)
|
||||
.padding(bottom = 16.dp, end = 16.dp)
|
||||
.background(
|
||||
color = Color.White,
|
||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
|
||||
)
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onDismissRequest
|
||||
) {
|
||||
//TODO - hardcode string
|
||||
Text(
|
||||
text = "Отмена"
|
||||
)
|
||||
}
|
||||
|
||||
TextButton(
|
||||
onClick = {
|
||||
onDateSelected(selDate.value)
|
||||
onDismissRequest()
|
||||
}
|
||||
) {
|
||||
//TODO - hardcode string
|
||||
Text(
|
||||
text = "Подтвердить"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,13 +7,14 @@ import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.ulstu.`is`.pmu.common.MyViewModel
|
||||
import ru.ulstu.`is`.pmu.common.TaskRepository
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
|
||||
class TaskEditViewModel(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val taskRepository: TaskRepository
|
||||
) : ViewModel() {
|
||||
) : MyViewModel() {
|
||||
|
||||
var taskUiState by mutableStateOf(TaskUiState())
|
||||
private set
|
||||
@ -21,11 +22,16 @@ class TaskEditViewModel(
|
||||
private val taskUid: Int = checkNotNull(savedStateHandle["id"])
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
if (taskUid > 0) {
|
||||
taskUiState = taskRepository.getTask(taskUid)
|
||||
.toUiState(true)
|
||||
}
|
||||
if (taskUid > 0) {
|
||||
runInScope(
|
||||
actionSuccess = {
|
||||
taskUiState = taskRepository.getTask(taskUid)
|
||||
.toUiState(true)
|
||||
},
|
||||
actionError = {
|
||||
taskUiState = TaskUiState()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,10 +41,9 @@ class TaskEditViewModel(
|
||||
isEntryValid = validateInput(taskDetails)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun saveTask() {
|
||||
fun saveTask() {
|
||||
if (validateInput()) {
|
||||
if (taskUid > 0) {
|
||||
runInScope ( actionSuccess = { if (taskUid > 0) {
|
||||
taskRepository.updateTask(
|
||||
taskUiState.taskDetails.toTask(taskUid)
|
||||
)
|
||||
@ -46,7 +51,8 @@ class TaskEditViewModel(
|
||||
taskRepository.insertTask(
|
||||
taskUiState.taskDetails.toTask()
|
||||
)
|
||||
}
|
||||
}
|
||||
} )
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +61,6 @@ class TaskEditViewModel(
|
||||
name.isNotBlank()
|
||||
&& description.isNotBlank()
|
||||
&& endDate.isNotBlank()
|
||||
&& userId > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,176 @@
|
||||
package ru.ulstu.is.pmu.ui.student.list
|
||||
package ru.ulstu.`is`.pmu.ui.task.list
|
||||
|
||||
class FavoriteTaskList {
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.DismissDirection
|
||||
import androidx.compose.material3.DismissState
|
||||
import androidx.compose.material3.DismissValue
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.SwipeToDismiss
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberDismissState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.paging.compose.itemContentType
|
||||
import androidx.paging.compose.itemKey
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.ulstu.`is`.pmu.common.AppViewModelProvider
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
import ru.ulstu.`is`.pmu.ui.navigation.Screen
|
||||
import ru.ulstu.`is`.pmu.ui.theme.PmudemoTheme
|
||||
|
||||
@Composable
|
||||
fun FavoriteTaskList(
|
||||
navController: NavController,
|
||||
viewModel: FavoriteTaskListViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val taskListUiState = viewModel.taskListUiState.collectAsLazyPagingItems()
|
||||
Scaffold(
|
||||
topBar = {}
|
||||
) { innerPadding ->
|
||||
FavoriteTaskList(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
taskList = taskListUiState
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun SwipeToDelete(
|
||||
task: Task
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 7.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = String.format("%s%n%s%n%s", task.name, task.description, task.endDate),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun FavoriteTaskList(
|
||||
modifier: Modifier = Modifier,
|
||||
taskList: LazyPagingItems<Task>
|
||||
) {
|
||||
val refreshScope = rememberCoroutineScope()
|
||||
var refreshing by remember { mutableStateOf(false) }
|
||||
fun refresh() = refreshScope.launch {
|
||||
refreshing = true
|
||||
taskList.refresh()
|
||||
refreshing = false
|
||||
}
|
||||
|
||||
val state = rememberPullRefreshState(refreshing, ::refresh)
|
||||
Box(
|
||||
modifier = modifier.pullRefresh(state)
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxSize()
|
||||
) {
|
||||
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||
items(
|
||||
count = taskList.itemCount,
|
||||
key = taskList.itemKey(),
|
||||
contentType = taskList.itemContentType()
|
||||
) { index ->
|
||||
val task = taskList[index]
|
||||
task?.let {
|
||||
SwipeToDelete(
|
||||
task = task
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
PullRefreshIndicator(
|
||||
refreshing, state,
|
||||
Modifier
|
||||
.align(CenterHorizontally)
|
||||
.zIndex(100f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Composable
|
||||
private fun TaskListItem(
|
||||
task: Task, modifier: Modifier = Modifier
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier.padding(all = 10.dp)
|
||||
) {
|
||||
Text(
|
||||
text = String.format("%s %s", task.name, task.description)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,15 @@
|
||||
package ru.ulstu.is.pmu.ui.student.list
|
||||
package ru.ulstu.`is`.pmu.ui.task.list
|
||||
|
||||
class FavoriteTaskListViewModel {
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.paging.PagingData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import ru.ulstu.`is`.pmu.common.MyViewModel
|
||||
import ru.ulstu.`is`.pmu.common.TaskRepository
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
|
||||
class FavoriteTaskListViewModel(
|
||||
private val taskRepository: TaskRepository
|
||||
) : MyViewModel() {
|
||||
|
||||
val taskListUiState: Flow<PagingData<Task>> = taskRepository.getAllFavoriteTasks()
|
||||
}
|
@ -16,11 +16,13 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.FavoriteBorder
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
@ -66,13 +68,20 @@ import ru.ulstu.`is`.pmu.common.AppViewModelProvider
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
import ru.ulstu.`is`.pmu.ui.navigation.Screen
|
||||
import ru.ulstu.`is`.pmu.ui.theme.PmudemoTheme
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
|
||||
@Composable
|
||||
fun TaskList(
|
||||
navController: NavController,
|
||||
viewModel: TaskListViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val taskListUiState = viewModel.taskListUiState.collectAsLazyPagingItems()
|
||||
Scaffold(
|
||||
topBar = {},
|
||||
@ -92,21 +101,15 @@ fun TaskList(
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(),
|
||||
taskList = taskListUiState,
|
||||
onClick = { uid: Int ->
|
||||
val route = Screen.TaskEdit.route.replace("{id}", uid.toString())
|
||||
navController.navigate(route)
|
||||
},
|
||||
onDeleteClick = { task: Task ->
|
||||
// Обработка удаления задачи
|
||||
coroutineScope.launch {
|
||||
viewModel.deleteTask(task)
|
||||
}
|
||||
taskListUiState.refresh()
|
||||
},
|
||||
onAddToFavoritesClick = { task: Task ->
|
||||
// Обработка добавления задачи в избранное
|
||||
coroutineScope.launch {
|
||||
viewModel.favoriteTask(task)
|
||||
}
|
||||
if(task.favorite == false) { viewModel.favoriteTask(task) } else viewModel.deletefavoriteTask(task)
|
||||
taskListUiState.refresh()
|
||||
},
|
||||
onEditClick = { task: Task ->
|
||||
// Обработка редактирования задачи
|
||||
@ -145,15 +148,66 @@ fun DismissBackground(dismissState: DismissState) {
|
||||
}
|
||||
}
|
||||
|
||||
fun calculateDaysDifference(endDate: Date, currentDate: Date): Int {
|
||||
try {
|
||||
val timeDifference = endDate.time - currentDate.time
|
||||
return (timeDifference / (24 * 60 * 60 * 1000)).toInt()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun SwipeToDelete(
|
||||
task: Task,
|
||||
onClick: (uid: Int) -> Unit,
|
||||
onDeleteClick: (task: Task) -> Unit,
|
||||
onAddToFavoritesClick: (task: Task) -> Unit,
|
||||
onEditClick: (task: Task) -> Unit
|
||||
) {
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
// Добавляем диалоговое окно для подтверждения удаления задачи
|
||||
if (showDialog) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black.copy(alpha = 0.5f)) // Меняем уровень прозрачности и цвет
|
||||
) {
|
||||
// Диалоговое окно
|
||||
AlertDialog(
|
||||
onDismissRequest = { showDialog = false },
|
||||
title = {
|
||||
Text(text = "Удаление задачи")
|
||||
},
|
||||
text = {
|
||||
Text(text = "Вы уверены, что хотите удалить эту задачу?")
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onDeleteClick(task)
|
||||
showDialog =
|
||||
false // Закрываем диалоговое окно после подтверждения удаления
|
||||
}
|
||||
) {
|
||||
Text(text = "Да")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
showDialog = false // Закрываем диалоговое окно без удаления задачи
|
||||
}
|
||||
) {
|
||||
Text(text = "Отмена")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -165,8 +219,35 @@ private fun SwipeToDelete(
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val currentDateString = SimpleDateFormat("dd.MM.yyyy").format(Date())
|
||||
val currentDate = SimpleDateFormat("dd.MM.yyyy").parse(currentDateString)
|
||||
|
||||
val taskName = task.name
|
||||
val taskDescription = task.description
|
||||
val endDate = SimpleDateFormat("dd.MM.yyyy").parse(task.endDate)
|
||||
|
||||
val isOverdue = currentDate.after(endDate)
|
||||
val overdueText = if (isOverdue) {
|
||||
val daysDifference = calculateDaysDifference(currentDate, endDate)
|
||||
val daysWord = if (daysDifference < 23) "дня" else "дней"
|
||||
"Задача просрочена на $daysDifference $daysWord"
|
||||
} else {
|
||||
task.endDate
|
||||
}
|
||||
|
||||
Text(
|
||||
text = String.format("%s %s", task.name, task.description),
|
||||
text = buildAnnotatedString {
|
||||
withStyle(style = SpanStyle(color = Color.Black)) {
|
||||
append("$taskName\n$taskDescription\n")
|
||||
}
|
||||
if (isOverdue) {
|
||||
withStyle(style = SpanStyle(color = Color.Red)) {
|
||||
append(overdueText)
|
||||
}
|
||||
} else {
|
||||
append(overdueText)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
@ -177,18 +258,18 @@ private fun SwipeToDelete(
|
||||
Icon(
|
||||
imageVector = Icons.Default.Edit,
|
||||
contentDescription = "Редактировать",
|
||||
tint = Color.Blue
|
||||
tint = Color.Black
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick = { onDeleteClick(task) },
|
||||
onClick = { showDialog = true }, // Показываем диалоговое окно при нажатии на кнопку удаления
|
||||
modifier = Modifier.padding(start = 8.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Delete,
|
||||
contentDescription = "Удалить",
|
||||
tint = Color.Red
|
||||
tint = Color.Black
|
||||
)
|
||||
}
|
||||
|
||||
@ -197,8 +278,9 @@ private fun SwipeToDelete(
|
||||
modifier = Modifier.padding(start = 8.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Favorite,
|
||||
contentDescription = "Добавить в избранное"
|
||||
imageVector = if (task.favorite) Icons.Default.Favorite else Icons.Default.FavoriteBorder,
|
||||
contentDescription = "Добавить в избранное",
|
||||
tint = Color.Black
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -210,7 +292,6 @@ private fun SwipeToDelete(
|
||||
private fun TaskList(
|
||||
modifier: Modifier = Modifier,
|
||||
taskList: LazyPagingItems<Task>,
|
||||
onClick: (uid: Int) -> Unit,
|
||||
onDeleteClick: (task: Task) -> Unit,
|
||||
onAddToFavoritesClick: (task: Task) -> Unit,
|
||||
onEditClick: (task: Task) -> Unit
|
||||
@ -240,7 +321,6 @@ private fun TaskList(
|
||||
task?.let {
|
||||
SwipeToDelete(
|
||||
task = task,
|
||||
onClick = onClick,
|
||||
onDeleteClick = onDeleteClick,
|
||||
onAddToFavoritesClick = onAddToFavoritesClick,
|
||||
onEditClick = onEditClick
|
||||
@ -257,23 +337,3 @@ private fun TaskList(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Composable
|
||||
private fun TaskListItem(
|
||||
task: Task, modifier: Modifier = Modifier
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier.padding(all = 10.dp)
|
||||
) {
|
||||
Text(
|
||||
text = String.format("%s %s", task.name, task.description)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -3,17 +3,25 @@ package ru.ulstu.`is`.pmu.ui.task.list
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.paging.PagingData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import ru.ulstu.`is`.pmu.common.MyViewModel
|
||||
import ru.ulstu.`is`.pmu.common.TaskRepository
|
||||
import ru.ulstu.`is`.pmu.database.task.model.Task
|
||||
|
||||
class TaskListViewModel(
|
||||
private val taskRepository: TaskRepository
|
||||
) : ViewModel() {
|
||||
) : MyViewModel() {
|
||||
|
||||
val taskListUiState: Flow<PagingData<Task>> = taskRepository.getAllTasks()
|
||||
val taskListUiState: Flow<PagingData<Task>> = taskRepository.getAllDateTasks()
|
||||
|
||||
suspend fun deleteTask(task: Task) {
|
||||
taskRepository.deleteTask(task)
|
||||
fun deleteTask(task: Task) {
|
||||
runInScope ( actionSuccess = {taskRepository.deleteTask(task)})
|
||||
}
|
||||
|
||||
fun favoriteTask(task: Task) {
|
||||
runInScope ( actionSuccess = {taskRepository.favoriteTask(task)})
|
||||
}
|
||||
|
||||
fun deletefavoriteTask(task: Task) {
|
||||
runInScope ( actionSuccess = {taskRepository.deletefavoriteTask(task)})
|
||||
}
|
||||
}
|
@ -1,16 +1,22 @@
|
||||
<resources>
|
||||
<string name="app_name">pmu-demo</string>
|
||||
<string name="task_firstname">Имя</string>
|
||||
<string name="task_lastname">Фамилия</string>
|
||||
<string name="task_user">Группа</string>
|
||||
<string name="task_phone">Телефон</string>
|
||||
<string name="task_firstname">Название задачи</string>
|
||||
<string name="task_lastname">Описание задачи</string>
|
||||
<string name="task_user">Пользователь</string>
|
||||
<string name="task_phone">Дата окончания</string>
|
||||
<string name="task_email">e-mail</string>
|
||||
<string name="task_main_title">Список студентов</string>
|
||||
<string name="task_main_title">Список задач</string>
|
||||
<string name="task_view_title">Профиль студента</string>
|
||||
<string name="task_favorite_view_title">Избранные</string>
|
||||
<string name="task_empty_description">Записи о студентах отсутствуют</string>
|
||||
<string name="task_user_not_select">Группа не указана</string>
|
||||
<string name="task_save_button">Сохранить</string>
|
||||
<string name="about_title">О нас</string>
|
||||
<string name="back">Назад</string>
|
||||
<string name="loading">Загрузка…</string>
|
||||
<string name="report">Отчет</string>
|
||||
<string name="startDate">Дата начала</string>
|
||||
<string name="endDate">Дата конца</string>
|
||||
<string name="about_text">
|
||||
<p>Это текст <b>о нас</b>!</p>\n\n
|
||||
<p>Здесь могла быть Ваша реклама!</p>\n\n
|
||||
|
42
server/.gitignore
vendored
42
server/.gitignore
vendored
@ -1,42 +0,0 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
@ -14,11 +14,15 @@
|
||||
"tasks": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "123456",
|
||||
"description": "32155",
|
||||
"endDate": "55",
|
||||
"favorite": false,
|
||||
"userId": 1
|
||||
"name": "dsads",
|
||||
"description": "12312312",
|
||||
"endDate": "02.11.2023"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "test",
|
||||
"description": "test",
|
||||
"endDate": "05.12.2023"
|
||||
}
|
||||
]
|
||||
}
|
629
server/package-lock.json
generated
629
server/package-lock.json
generated
@ -7,10 +7,26 @@
|
||||
"": {
|
||||
"name": "fake-db",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"pdfkit": "^0.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"json-server": "0.17.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.3.17",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz",
|
||||
"integrity": "sha512-tb7Iu+oZ+zWJZ3HJqwx8oNwSDIU440hmVMDPhpACWQWnrZHK99Bxs70gT1L2dnr5Hg50ZRWEFkQCAnOVVV0z1Q==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers/node_modules/tslib": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
@ -48,12 +64,54 @@
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/array-buffer-byte-length": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
|
||||
"integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"is-array-buffer": "^3.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
|
||||
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/basic-auth": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
|
||||
@ -90,6 +148,14 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/brotli": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
|
||||
"integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
@ -103,7 +169,6 @@
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz",
|
||||
"integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.1",
|
||||
@ -143,6 +208,14 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@ -278,6 +351,11 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
@ -287,11 +365,46 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-equal": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
|
||||
"integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
|
||||
"dependencies": {
|
||||
"array-buffer-byte-length": "^1.0.0",
|
||||
"call-bind": "^1.0.5",
|
||||
"es-get-iterator": "^1.1.3",
|
||||
"get-intrinsic": "^1.2.2",
|
||||
"is-arguments": "^1.1.1",
|
||||
"is-array-buffer": "^3.0.2",
|
||||
"is-date-object": "^1.0.5",
|
||||
"is-regex": "^1.1.4",
|
||||
"is-shared-array-buffer": "^1.0.2",
|
||||
"isarray": "^2.0.5",
|
||||
"object-is": "^1.1.5",
|
||||
"object-keys": "^1.1.1",
|
||||
"object.assign": "^4.1.4",
|
||||
"regexp.prototype.flags": "^1.5.1",
|
||||
"side-channel": "^1.0.4",
|
||||
"which-boxed-primitive": "^1.0.2",
|
||||
"which-collection": "^1.0.1",
|
||||
"which-typed-array": "^1.1.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-equal/node_modules/isarray": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz",
|
||||
"integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.1",
|
||||
"gopd": "^1.0.1",
|
||||
@ -301,6 +414,22 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
@ -320,6 +449,11 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/dfa": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
|
||||
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
@ -354,6 +488,30 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/es-get-iterator": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
|
||||
"integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"get-intrinsic": "^1.1.3",
|
||||
"has-symbols": "^1.0.3",
|
||||
"is-arguments": "^1.1.1",
|
||||
"is-map": "^2.0.2",
|
||||
"is-set": "^2.0.2",
|
||||
"is-string": "^1.0.7",
|
||||
"isarray": "^2.0.5",
|
||||
"stop-iteration-iterator": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/es-get-iterator/node_modules/isarray": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
@ -516,6 +674,30 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fontkit": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.9.0.tgz",
|
||||
"integrity": "sha512-HkW/8Lrk8jl18kzQHvAw9aTHe1cqsyx5sDnxncx652+CIfhawokEPkeM3BoIC+z/Xv7a0yMr0f3pRRwhGH455g==",
|
||||
"dependencies": {
|
||||
"@swc/helpers": "^0.3.13",
|
||||
"brotli": "^1.3.2",
|
||||
"clone": "^2.1.2",
|
||||
"deep-equal": "^2.0.5",
|
||||
"dfa": "^1.2.0",
|
||||
"restructure": "^2.0.1",
|
||||
"tiny-inflate": "^1.0.3",
|
||||
"unicode-properties": "^1.3.1",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
|
||||
"dependencies": {
|
||||
"is-callable": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
@ -538,7 +720,14 @@
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/functions-have-names": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
||||
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@ -556,7 +745,6 @@
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
|
||||
"integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2",
|
||||
"has-proto": "^1.0.1",
|
||||
@ -571,7 +759,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.1.3"
|
||||
},
|
||||
@ -585,6 +772,14 @@
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/has-bigints": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
|
||||
"integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
@ -598,7 +793,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.2"
|
||||
},
|
||||
@ -610,7 +804,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@ -622,7 +815,20 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
|
||||
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@ -634,7 +840,6 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
|
||||
"integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
@ -676,6 +881,19 @@
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/internal-slot": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz",
|
||||
"integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.2",
|
||||
"hasown": "^2.0.0",
|
||||
"side-channel": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
@ -685,6 +903,85 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arguments": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-array-buffer": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
|
||||
"integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"get-intrinsic": "^1.2.0",
|
||||
"is-typed-array": "^1.1.10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-bigint": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
|
||||
"integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
|
||||
"dependencies": {
|
||||
"has-bigints": "^1.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-boolean-object": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
|
||||
"integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-callable": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-date-object": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
|
||||
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
|
||||
"dependencies": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
@ -694,12 +991,130 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-map": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
|
||||
"integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number-object": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
|
||||
"integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
|
||||
"dependencies": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-promise": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
|
||||
"integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/is-regex": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
|
||||
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-set": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
|
||||
"integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-shared-array-buffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
|
||||
"integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-string": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
|
||||
"integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
|
||||
"dependencies": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-symbol": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
|
||||
"integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-typed-array": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz",
|
||||
"integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==",
|
||||
"dependencies": {
|
||||
"which-typed-array": "^1.1.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-weakmap": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
|
||||
"integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-weakset": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
|
||||
"integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"get-intrinsic": "^1.1.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
@ -754,6 +1169,23 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/linebreak": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
|
||||
"integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
|
||||
"dependencies": {
|
||||
"base64-js": "0.0.8",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/linebreak/node_modules/base64-js": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
|
||||
"integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
@ -940,7 +1372,46 @@
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
|
||||
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-is": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
|
||||
"integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/object.assign": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
|
||||
"integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.5",
|
||||
"define-properties": "^1.2.1",
|
||||
"has-symbols": "^1.0.3",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@ -981,6 +1452,17 @@
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/pdfkit": {
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.14.0.tgz",
|
||||
"integrity": "sha512-Hnor8/78jhHm6ONrxWhrqOwAVALlBnFyWOF8sstBZMiqHZgZ5A6RU+Q3yahhw82plxpT7LOfH3b3qcOX6rzMQg==",
|
||||
"dependencies": {
|
||||
"crypto-js": "^4.2.0",
|
||||
"fontkit": "^1.8.1",
|
||||
"linebreak": "^1.0.2",
|
||||
"png-js": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
@ -1008,6 +1490,11 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/png-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
|
||||
"integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@ -1060,6 +1547,22 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz",
|
||||
"integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.2.0",
|
||||
"set-function-name": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
@ -1069,6 +1572,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/restructure": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz",
|
||||
"integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg=="
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
@ -1142,7 +1650,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
|
||||
"integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.1",
|
||||
"get-intrinsic": "^1.2.1",
|
||||
@ -1153,6 +1660,19 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/set-function-name": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz",
|
||||
"integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"functions-have-names": "^1.2.3",
|
||||
"has-property-descriptors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
@ -1163,7 +1683,6 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
@ -1191,6 +1710,17 @@
|
||||
"graceful-fs": "^4.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/stop-iteration-iterator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
|
||||
"integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
|
||||
"dependencies": {
|
||||
"internal-slot": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
@ -1229,6 +1759,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-inflate": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
|
||||
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
@ -1251,6 +1786,29 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-properties": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
|
||||
"integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-trie": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
||||
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
|
||||
"dependencies": {
|
||||
"pako": "^0.2.5",
|
||||
"tiny-inflate": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-trie/node_modules/pako": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
|
||||
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
@ -1278,6 +1836,53 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/which-boxed-primitive": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
|
||||
"integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
|
||||
"dependencies": {
|
||||
"is-bigint": "^1.0.1",
|
||||
"is-boolean-object": "^1.1.0",
|
||||
"is-number-object": "^1.0.4",
|
||||
"is-string": "^1.0.5",
|
||||
"is-symbol": "^1.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/which-collection": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
|
||||
"integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
|
||||
"dependencies": {
|
||||
"is-map": "^2.0.1",
|
||||
"is-set": "^2.0.1",
|
||||
"is-weakmap": "^2.0.1",
|
||||
"is-weakset": "^2.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/which-typed-array": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz",
|
||||
"integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==",
|
||||
"dependencies": {
|
||||
"available-typed-arrays": "^1.0.5",
|
||||
"call-bind": "^1.0.4",
|
||||
"for-each": "^0.3.3",
|
||||
"gopd": "^1.0.1",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
|
@ -2,9 +2,10 @@
|
||||
"name": "fake-db",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"start": "json-server --watch data.json --host 0.0.0.0 -p 8079"
|
||||
"start": "json-server --watch data.json --middlewares ./server.js --host 0.0.0.0 -p 8079"
|
||||
},
|
||||
"dependencies": {
|
||||
"pdfkit": "^0.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"json-server": "0.17.4"
|
||||
|
Loading…
Reference in New Issue
Block a user