Compare commits

..
12 Commits
Author SHA1 Message Date
Agzamus 99e05e8232 ui: surfaceContainer background 2026-09-10 01:36:24 +03:00
Agzamus c4ecc43597 ui: canged colors 2026-09-10 01:01:57 +03:00
Agzamus 9a96bd3dac ci: installing from /github.com/adoptium 2026-09-10 00:47:38 +03:00
Agzamus c4345f9dbe ci: bullseye repo archive mirror 2026-09-10 00:44:18 +03:00
Agzamus 4797811097 ci: ignore jdk Check-Valid-Until 2026-09-10 00:31:17 +03:00
Agzamus 2dfef426a7 ui: schedule striped copyable rows 2026-09-10 00:23:28 +03:00
Agzamus 97c19647cc ui: LessonSlot separator 2026-09-09 22:25:55 +03:00
Agzamus dea27bc8f1 ci: fixed workflow old apt jdk17 repo 2026-09-07 00:35:50 +03:00
Agzamus bafebfd253 fix: no auto download if updated disabled 2026-09-07 00:31:34 +03:00
Agzamus f19d65abb5 feat: update request when need 2026-09-06 17:23:55 +03:00
Agzamus 889c57bbba feat: autoupdater 2026-09-06 12:38:00 +03:00
Agzamus ec6a7174e8 feat: icon & name 2026-09-06 02:47:40 +03:00
33 changed files with 509 additions and 148 deletions
+11 -3
View File
@@ -30,9 +30,17 @@ jobs:
# Ставим JDK вручную и явно прописываем JAVA_HOME.
# actions/setup-java не всегда передаёт JAVA_HOME дальше в Gitea Actions.
run: |
apt-get update
apt-get install -y openjdk-17-jdk-headless unzip wget
echo "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64" >> "$GITHUB_ENV"
set -euxo pipefail
cd /tmp
wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.12%2B7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.12_7.tar.gz
tar -xzf OpenJDK17U-jdk_x64_linux_hotspot_17.0.12_7.tar.gz -C /opt
mv /opt/jdk-17.0.12+7 /opt/java17
export JAVA_HOME=/opt/java17
export PATH=$JAVA_HOME/bin:$PATH
echo "JAVA_HOME=/opt/java17" >> $GITHUB_ENV
echo "$JAVA_HOME/bin" >> $GITHUB_PATH
java -version
javac -version
- name: Install Android SDK
# Устанавливаем command-line tools и нужные компоненты SDK,
+1 -5
View File
@@ -1,6 +1,2 @@
# vyatsu-schedulegit
# vyatsu-schedule
## settings-branch
blank settings at first, soon will add update feature.
settings will be presetned as fourth button on the bottom of the screen.
+1 -1
View File
@@ -10,7 +10,7 @@
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

+27
View File
@@ -6,6 +6,9 @@ import agzam.vyatsu.ui.groups.GroupPickerViewModel
import agzam.vyatsu.ui.home.HomeScreen
import agzam.vyatsu.ui.schedule.ScheduleViewModel
import agzam.vyatsu.ui.settings.UpdateViewModel
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@@ -24,6 +27,30 @@ fun AppRoot() {
val updateViewModel: UpdateViewModel = viewModel(factory = updateFactory(container))
val state by scheduleViewModel.uiState.collectAsState()
val showFirstRunDialog by updateViewModel.showFirstRunDialog.collectAsState()
if (showFirstRunDialog) {
AlertDialog(
onDismissRequest = { updateViewModel.onFirstRunDecision(false) },
title = { Text("Автоматические обновления") },
text = {
Text(
"Разрешить автоматически проверять и устанавливать " +
"новые версии приложения?"
)
},
confirmButton = {
TextButton(onClick = { updateViewModel.onFirstRunDecision(true) }) {
Text("Разрешить")
}
},
dismissButton = {
TextButton(onClick = { updateViewModel.onFirstRunDecision(false) }) {
Text("Не надо")
}
}
)
}
if (state.noGroup) {
GroupPickerScreen(
@@ -33,4 +33,10 @@ interface PreferencesDao {
@Query("INSERT OR REPLACE INTO preferences(key, value) VALUES('autoUpdateEnabled', :enabled)")
suspend fun setAutoUpdateEnabled(enabled: String)
@Query("SELECT value FROM preferences WHERE key = 'autoUpdateAsked'")
suspend fun autoUpdateAsked(): String?
@Query("INSERT OR REPLACE INTO preferences(key, value) VALUES('autoUpdateAsked', :asked)")
suspend fun setAutoUpdateAsked(asked: String)
}
@@ -14,6 +14,9 @@ class PreferencesRepositoryImpl(
override suspend fun selectedDayDate(): String? = dao.selectedDayDate()
override suspend fun setSelectedDayDate(date: String) = dao.setSelectedDayDate(date)
override suspend fun autoUpdateEnabled(): Boolean = dao.autoUpdateEnabled() != "false"
override suspend fun autoUpdateEnabled(): Boolean = dao.autoUpdateEnabled() == "true"
override suspend fun setAutoUpdateEnabled(enabled: Boolean) = dao.setAutoUpdateEnabled(enabled.toString())
override suspend fun autoUpdateAsked(): Boolean = dao.autoUpdateAsked() == "true"
override suspend fun setAutoUpdateAsked(asked: Boolean) = dao.setAutoUpdateAsked(asked.toString())
}
@@ -11,4 +11,7 @@ interface PreferencesRepository {
suspend fun autoUpdateEnabled(): Boolean
suspend fun setAutoUpdateEnabled(enabled: Boolean)
suspend fun autoUpdateAsked(): Boolean
suspend fun setAutoUpdateAsked(asked: Boolean)
}
@@ -4,23 +4,31 @@ import agzam.vyatsu.domain.model.Day
import agzam.vyatsu.domain.model.LessonType
import agzam.vyatsu.domain.model.SchedulePeriod
import agzam.vyatsu.domain.model.TimeSlot
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.Refresh
@@ -33,6 +41,7 @@ import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
@@ -46,14 +55,20 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import java.time.DayOfWeek
import java.time.LocalDate
import java.time.format.DateTimeFormatter
val hPadding = 16.dp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
val state by viewModel.uiState.collectAsState()
Column(Modifier.fillMaxSize()) {
@@ -69,7 +84,7 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
},
windowInsets = WindowInsets(0.dp)
)
Column(Modifier.fillMaxSize().padding(horizontal = 16.dp, vertical = 0.dp)) {
Column(Modifier.fillMaxSize().padding(horizontal = 0.dp, vertical = 0.dp)) {
when {
state.isSyncing && state.schedule == null -> {
Row(
@@ -110,7 +125,7 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
val dayLabel = if (isTodayDay) "Сегодня " else ""
Row(
Modifier.fillMaxWidth(),
Modifier.fillMaxWidth().padding(horizontal = hPadding),
verticalAlignment = Alignment.CenterVertically
) {
Text(
@@ -125,7 +140,7 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
onSelect = viewModel::selectWeek
)
}
HorizontalDivider(Modifier.padding(top = 8.dp, bottom = 0.dp))
HorizontalDivider(Modifier.padding(top = 8.dp, bottom = 0.dp, start = hPadding, end = hPadding))
DayChips(
days = weekDays,
@@ -134,14 +149,14 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
onSelect = viewModel::selectDay
)
HorizontalDivider(Modifier.padding(top=0.dp, bottom = 8.dp))
HorizontalDivider(Modifier.padding(top=0.dp, start = hPadding, end = hPadding))
if (day.intervals.all { it.lessons.isEmpty() }) {
Text("Занятий нет", style = MaterialTheme.typography.bodyLarge)
} else {
LazyColumn(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(8.dp)
verticalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(vertical = 8.dp)
) {
itemsIndexed(day.intervals) { slotIndex, slot ->
LessonSlot(slotIndex = slotIndex, slot = slot)
@@ -227,7 +242,7 @@ private fun DayChips(
todayDate: LocalDate?,
onSelect: (LocalDate) -> Unit
) {
LazyRow(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
LazyRow(horizontalArrangement = Arrangement.spacedBy(6.dp), contentPadding = PaddingValues(horizontal = hPadding, vertical = 2.dp),) {
items(days, key = { it.date.toEpochDay() }) { day ->
val selected = selectedDate == day.date
val isTodayChip = todayDate == day.date
@@ -275,59 +290,97 @@ private fun weekLabel(period: SchedulePeriod): String {
@Composable
private fun LessonSlot(slotIndex: Int, slot: TimeSlot) {
val context = LocalContext.current
var indexColor = 0
Column(Modifier.fillMaxWidth()) {
Text(
"${slotIndex + 1} пара · ${slot.start.format(TIME)}–${slot.end.format(TIME)}",
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.primary
)
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
HorizontalDivider(
modifier = Modifier.width(10.dp + hPadding).padding(start = hPadding),
color = MaterialTheme.colorScheme.primary
)
Text(
"${slotIndex + 1} пара · ${slot.start.format(TIME)}–${slot.end.format(TIME)}",
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(horizontal = 4.dp)
)
HorizontalDivider(color = MaterialTheme.colorScheme.primary, modifier = Modifier.weight(1f).padding(end = hPadding))
}
if (slot.lessons.isEmpty()) {
Text("—", style = MaterialTheme.typography.bodyMedium)
} else {
slot.lessons.forEach { lesson ->
Column(Modifier.fillMaxWidth().padding(vertical = 2.dp)) {
var any = false
if(lesson.type != LessonType.OTHER) {
Text(
lesson.type.label,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
any = true
slot.lessons.forEachIndexed { index, lesson ->
var baseSurface = Modifier.fillMaxWidth().padding(vertical = 2.dp)
if ((indexColor) % 2 != 0) {
baseSurface = baseSurface.background(
MaterialTheme.colorScheme.surfaceContainer
);
}
indexColor++
// XXX:
// Убрать SelectionContainer?
// Режим редактирования расписания?
// Меню на onClick?
// Меню на onLongClick?
SelectionContainer() {
Column(
baseSurface
// XXX: combinedClickable?
//.combinedClickable(
// onClick = {
// Toast.makeText(
// context,
// lesson.raw,
// Toast.LENGTH_SHORT
// ).show()
// },
// onLongClick = {},
// // TODO: onLongClickLabel = "(Accessibility)"
//),
) {
var any = false
val meta = listOfNotNull(
if (lesson.type == LessonType.OTHER) {
null
} else {
lesson.type.label
},
lesson.subgroup,
lesson.teacher,
lesson.room
).filter { it.isNotBlank() }.joinToString(" · ")
if (meta.isNotEmpty()) {
Text(
meta,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = hPadding)
)
any = true
}
val subject = lesson.subject?.takeIf { it.isNotBlank() } ?: lesson.raw
if (subject.isNotEmpty()) {
Text(
subject,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(horizontal = hPadding)
)
any = true
}
if (!any) {
Text(
"пусто",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = hPadding)
)
}
}
val subject = lesson.subject?.takeIf { it.isNotBlank() } ?: lesson.raw
if(subject.isNotEmpty()) {
Text(
subject,
style = MaterialTheme.typography.bodyLarge
)
any = true
}
val meta = listOfNotNull(
lesson.subgroup,
lesson.teacher,
lesson.room
).filter { it.isNotBlank() }.joinToString(" · ")
if(meta.isNotEmpty()) {
Text(
meta,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
any = true
}
if(!any) {
Text(
"-",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
@@ -50,12 +50,12 @@ fun SettingsScreen(viewModel: UpdateViewModel) {
item {
SettingsItem(
title = "Проверить наличие обновлений",
subtitle = updateStatusText(updateState),
subtitle = updateStatusText(updateState, autoEnabled),
onClick = { viewModel.checkNow() }
)
SettingsDivider()
}
if (updateState is UpdateState.Available || updateState is UpdateState.ReadyToInstall) {
if (autoEnabled && (updateState is UpdateState.Available || updateState is UpdateState.ReadyToInstall)) {
item {
SettingsItem(
title = "Установить обновление",
@@ -89,11 +89,13 @@ fun SettingsScreen(viewModel: UpdateViewModel) {
}
}
private fun updateStatusText(state: UpdateState): String = when (state) {
private fun updateStatusText(state: UpdateState, autoEnabled: Boolean): String = when (state) {
is UpdateState.Idle -> "Проверить сейчас"
is UpdateState.Checking -> "Проверка…"
is UpdateState.UpToDate -> "Установлена последняя версия"
is UpdateState.Available -> "Доступна версия ${state.version}"
is UpdateState.Available ->
if (autoEnabled) "Доступна версия ${state.version}"
else "Доступна версия ${state.version} — включите автообновления для установки"
is UpdateState.Downloading -> "Скачивание: ${state.progress?.let { "$it%" } ?: "…"}"
is UpdateState.ReadyToInstall -> "Обновление скачано, нажмите для установки"
is UpdateState.Failed -> "Ошибка: ${state.message}"
@@ -17,18 +17,33 @@ class UpdateViewModel(
val updateState: StateFlow<UpdateState> = updater.state
private val _autoEnabled = MutableStateFlow(true)
private val _autoEnabled = MutableStateFlow(false)
val autoEnabled: StateFlow<Boolean> = _autoEnabled.asStateFlow()
private val _showFirstRunDialog = MutableStateFlow(false)
val showFirstRunDialog: StateFlow<Boolean> = _showFirstRunDialog.asStateFlow()
init {
viewModelScope.launch {
_autoEnabled.value = preferencesRepository.autoUpdateEnabled()
_showFirstRunDialog.value = !preferencesRepository.autoUpdateAsked()
}
}
fun setAutoEnabled(enabled: Boolean) {
_autoEnabled.value = enabled
updater.setAutoEnabled(enabled)
if (enabled && !updater.canRequestInstalls()) {
updater.openUnknownSourcesSettings()
}
}
fun onFirstRunDecision(enable: Boolean) {
_showFirstRunDialog.value = false
viewModelScope.launch {
preferencesRepository.setAutoUpdateAsked(true)
}
setAutoEnabled(enable)
}
fun checkNow() = updater.checkForUpdate()
@@ -9,6 +9,7 @@ import android.net.Uri
import android.provider.Settings
import android.util.Log
import androidx.core.content.FileProvider
import kotlin.coroutines.cancellation.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -75,6 +76,7 @@ class AppUpdater(
if (job?.isActive == true) return
val update = pendingUpdate ?: return
job = scope.launch {
if (!preferencesRepository.autoUpdateEnabled()) return@launch
runCatching { install(download(update)) }.onFailure(::onUpdateFailed)
}
}
@@ -85,6 +87,12 @@ class AppUpdater(
}
fun setAutoEnabled(enabled: Boolean) {
if (!enabled) {
job?.cancel()
if (_state.value is UpdateState.Downloading || _state.value is UpdateState.Checking) {
_state.value = UpdateState.Idle
}
}
scope.launch {
preferencesRepository.setAutoUpdateEnabled(enabled)
}
@@ -166,7 +174,6 @@ class AppUpdater(
private fun install(apk: File) {
if (!canRequestInstalls()) {
openUnknownSourcesSettings()
return
}
val uri = FileProvider.getUriForFile(
@@ -184,6 +191,7 @@ class AppUpdater(
}
private fun onUpdateFailed(error: Throwable) {
if (error is CancellationException) throw error
Log.e(TAG, "Ошибка обновления", error)
_state.value = UpdateState.Failed(error.message ?: "Неизвестная ошибка")
}
@@ -1,74 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:viewportHeight="108"
android:height="108dp"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
+109
View File
@@ -0,0 +1,109 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="100dp"
android:height="100dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M1,6L1,18L19,18L19,6"
android:strokeLineJoin="round"
android:strokeWidth="0"
android:strokeLineCap="round">
<aapt:attr name="android:fillColor">
<gradient
android:startX="1"
android:startY="18"
android:endX="19"
android:endY="6"
android:type="linear">
<item android:offset="0" android:color="#FF5581D5"/>
<item android:offset="1" android:color="#FF4063CD"/>
</gradient>
</aapt:attr>
<aapt:attr name="android:strokeColor">
<gradient
android:startX="1"
android:startY="18"
android:endX="19"
android:endY="6"
android:type="linear">
<item android:offset="0" android:color="#FF5581D5"/>
<item android:offset="1" android:color="#FF4063CD"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M19,18L1,18C12,18 19,14 19,6Z"
android:strokeLineJoin="round"
android:strokeWidth="0"
android:strokeLineCap="round">
<aapt:attr name="android:fillColor">
<gradient
android:startX="1"
android:startY="18"
android:endX="19"
android:endY="6"
android:type="linear">
<item android:offset="0" android:color="#FF6598E3"/>
<item android:offset="1" android:color="#FF74A2E6"/>
</gradient>
</aapt:attr>
<aapt:attr name="android:strokeColor">
<gradient
android:startX="1"
android:startY="18"
android:endX="19"
android:endY="6"
android:type="linear">
<item android:offset="0" android:color="#FF6598E3"/>
<item android:offset="1" android:color="#FF74A2E6"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M4,4C4,2 6,2 6,4L14,4C14,2 16,2 16,4L19,4L19,6L1,6L1,4Z"
android:strokeLineJoin="round"
android:strokeWidth="0"
android:strokeLineCap="round">
<aapt:attr name="android:fillColor">
<gradient
android:startX="1"
android:startY="2.5"
android:endX="19"
android:endY="2.5"
android:type="linear">
<item android:offset="0" android:color="#FF4260C4"/>
<item android:offset="1" android:color="#FF0E2CB0"/>
</gradient>
</aapt:attr>
<aapt:attr name="android:strokeColor">
<gradient
android:startX="1"
android:startY="2.5"
android:endX="19"
android:endY="2.5"
android:type="linear">
<item android:offset="0" android:color="#FF4260C4"/>
<item android:offset="1" android:color="#FF0E2CB0"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M3,8L17,8C18,8 18,9 17,9L3,9C2,9 2,8 3,8M3,11L14,11C15,11 15,12 14,12L3,12C2,12 2,11 3,11M4,14L12,14C13,14 13,15 12,15L5,15C4,15 4,14 5,14M3,14C4,14 4,15 3,15C2,15 2,14 3,14"
android:strokeLineJoin="round"
android:strokeWidth="0"
android:strokeColor="#00000000"
android:strokeLineCap="round">
<aapt:attr name="android:fillColor">
<gradient
android:startX="2.25"
android:startY="8"
android:endX="17.75"
android:endY="8"
android:type="linear">
<item android:offset="0" android:color="#FF4260C4"/>
<item android:offset="1" android:color="#FF0E2CB0"/>
</gradient>
</aapt:attr>
</path>
</vector>
+35
View File
@@ -0,0 +1,35 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100px" height="100px" viewBox="-10 -10 20 20">
<defs>
<linearGradient id="accent">
<stop offset="0%" stop-color="#4260c4" />
<stop offset="100%" stop-color="#0e2cb0" />
</linearGradient>
<linearGradient id="bg" x1="0%" y1="100%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#5581d5" />
<stop offset="100%" stop-color="#4063cd" />
</linearGradient>
<linearGradient id="bga" x1="0%" y1="100%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#6598e3" />
<stop offset="100%" stop-color="#74a2e6" />
</linearGradient>
</defs>
<g stroke-width="0" stroke-linejoin="round" stroke-linecap="round">
<!-- <path stroke="#111" d="M -9 -4 L -9 8 L 9 8 L 9 -4"/> -->
<path stroke="url(#bg)" fill="url(#bg)" d="M -9 -4 L -9 8 L 9 8 L 9 -4"/>
<path stroke="url(#bga)" fill="url(#bga)" d="M 9 8 L -9 8 C 2 8 9 4 9 -4 Z"/>
<!-- <path stroke="#111" d="M -6 -6 C -6 -8 -4 -8 -4 -6 L 4 -6 C 4 -8 6 -8 6 -6 L 9 -6 L 9 -4 L -9 -4 L -9 -6 Z"/> -->
<g stroke="url(#accent)">
<path fill="url(#accent)" d="M -6 -6 C -6 -8 -4 -8 -4 -6 L 4 -6 C 4 -8 6 -8 6 -6 L 9 -6 L 9 -4 L -9 -4 L -9 -6 Z"/>
<path fill="url(#accent)" stroke="none" d="M -7 -2 L 7 -2 C 8 -2 8 -1 7 -1 L -7 -1 C -8 -1 -8 -2 -7 -2 M -7 1 L 4 1 C 5 1 5 2 4 2 L -7 2 C -8 2 -8 1 -7 1 M -6 4 L 2 4 C 3 4 3 5 2 5 L -5 5 C -6 5 -6 4 -5 4 M -7 4 C -6 4 -6 5 -7 5 C -8 5 -8 4 -7 4"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

+1 -1
View File
@@ -1,3 +1,3 @@
<resources>
<string name="app_name">VyatsuSchedule</string>
<string name="app_name">ВятГУ Расписание</string>
</resources>