Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/android-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Android CI

on:
push:
branches:
- main
- 'feature/**'
pull_request:
branches:
- '*'

jobs:
build-and-test:
runs-on: macos-latest
env:
ANDROID_SDK_ROOT: /Users/runner/Library/Android/sdk

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*','**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 17

- name: Install Android SDK
uses: android-actions/setup-android@v2
with:
api-level: 33
build-tools: "33.0.2"
components: |
platform-tools
emulator
tools
platforms;android-33
system-images;android-33;google_apis;x86_64

- name: Accept Android SDK licenses
run: yes | sdkmanager --licenses

- name: Create and start emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 33
target: google_apis
arch: x86_64
force-avd-creation: true
emulator-options: -no-window -no-boot-anim -gpu swiftshader_indirect
disable-animations: true
emulator-boot-timeout: 180

- name: Build debug APK, run unit & instrumentation tests
run: |
./gradlew clean assembleDebug \
testDebugUnitTest \
connectedDebugAndroidTest \
--stacktrace
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ android {

dependencies {
testImplementation(libs.mockk)
testImplementation(libs.jupiter.junit.jupiter)
androidTestImplementation(libs.ui.test.junit4)
debugImplementation(libs.ui.test.manifest)
implementation(libs.androidx.lifecycle.process)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package org.hse.smartcalendar.ui.screens

import androidx.compose.ui.test.*
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.datetime.LocalTime
import org.hse.smartcalendar.data.DailyTask
import org.hse.smartcalendar.data.DailyTaskType
import org.hse.smartcalendar.store.StatisticsStore
import org.hse.smartcalendar.ui.screens.model.AchievementType
import org.hse.smartcalendar.ui.theme.SmartCalendarTheme
import org.hse.smartcalendar.utility.TimeUtils
import org.hse.smartcalendar.utility.fromMinutesOfDay
import org.hse.smartcalendar.utility.rememberNavigation
import org.hse.smartcalendar.view.model.AbstractListViewModel
import org.hse.smartcalendar.view.model.StatisticsViewModel
import org.hse.smartcalendar.view.model.StatisticsManager
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.UUID
@RunWith(AndroidJUnit4::class)
class AchievementsScreenTest {
private lateinit var firstTask: DailyTask
private lateinit var secondTask: DailyTask
@get:Rule
val composeTestRule = createComposeRule()
@Before
fun initTasks(){
StatisticsStore.uploader={}
firstTask = DailyTask(
title = "first",
id = UUID.randomUUID(),
isComplete = false,
type = DailyTaskType.COMMON,
creationTime = TimeUtils.Companion.getCurrentDateTime(),
description = "",
start = LocalTime.Companion.fromMinutesOfDay(0),
end = LocalTime.Companion.fromMinutesOfDay(300),
date = TimeUtils.Companion.getCurrentDateTime().date,
)
secondTask = DailyTask(
title = "first",
id = UUID.randomUUID(),
isComplete = false,
type = DailyTaskType.WORK,
creationTime = TimeUtils.Companion.getCurrentDateTime(),
description = "",
start = LocalTime.Companion.fromMinutesOfDay(300),
end = LocalTime.Companion.fromMinutesOfDay(1440-1),
date = TimeUtils.Companion.getCurrentDateTime().date,
)
}
fun assertAchievementData(type: AchievementType, text: String){
composeTestRule
.onNodeWithTag(type.testTag)
.onChildren()
.filter(hasText(text))
.onFirst()
.assertExists()
}
@Test
fun achievementsShowsStreak() {
val statisticsViewModel = StatisticsViewModel()
val listViewModel = AbstractListViewModel(StatisticsManager(statisticsViewModel))
//нужно потестить каждый элемент:Planning everything - без заданий 0,
// с заданием 5ч 5/10, c 24ч 24 часа
composeTestRule.setContent {
SmartCalendarTheme {
AchievementsScreen(
navigation = rememberNavigation(),
openDrawer = {},
statisticsModel = statisticsViewModel
)
}
}

composeTestRule.onNodeWithText("Eternal Flame").assertIsDisplayed()
listViewModel.addDailyTask(firstTask)
composeTestRule.runOnIdle {
}
assertAchievementData(AchievementType.PlanToday, "5/10")
assertAchievementData(AchievementType.CommonSpend, "0/10")
listViewModel.changeTaskCompletion(firstTask, true)
assert(statisticsViewModel.uiState.value.total.Common.toMinutes().toInt() == firstTask.getMinutesLength())
composeTestRule.runOnIdle {}
assertAchievementData(AchievementType.CommonSpend, "5/10")
assertAchievementData(AchievementType.Streak, "1/5")
listViewModel.addDailyTask(secondTask)
composeTestRule.runOnIdle {}
assertAchievementData(AchievementType.PlanToday, "24/24")
assertAchievementData(AchievementType.Streak, "0/5")
}
}
// assertAchievementData(AchievementType.CommonSpend, "0/10")
// assertAchievementData(AchievementType.PlanToday, "5/10")
// listViewModel.changeTaskCompletion(firstTask, true)
// assertAchievementData(AchievementType.CommonSpend, "5/10")
// listViewModel.addDailyTask(secondTask)
// composeTestRule.runOnIdle {}
// assertAchievementData(AchievementType.PlanToday, "24/24")
// listViewModel.changeTaskCompletion(secondTask, true)
// composeTestRule.runOnIdle {}
// assertAchievementData(AchievementType.WorkWeek, (24/7).toInt().toString()+"/${AchievementType.WorkWeek.levels[0]}")
// }
//}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.hse.smartcalendar.ui.screens

import androidx.activity.ComponentActivity
import androidx.compose.ui.semantics.ProgressBarRangeInfo
import androidx.compose.ui.test.*
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.junit4.createComposeRule
import org.hse.smartcalendar.ui.screens.model.AchievementType
import org.junit.Rule
import org.junit.Test

class AchievementCardTest {
val type = AchievementType.PlanToday
val tag = type.testTag
@get:Rule
val composeTestRule = createComposeRule()

@Test
fun nullProgress() {
composeTestRule.setContent {//cannot setContent twice
AchievementCard(data = type, parameter = 0L)
}
composeTestRule.onNode(
hasText("Plan ${type.levels[0]} hours of your time today")
.and(hasParent(hasTestTag(tag)))
).assertExists()
}
@Test fun mediumProgress() {
composeTestRule.setContent {
AchievementCard(data = type, parameter = 6L)
}
composeTestRule.onNodeWithTag("${tag}_progress")
.assertIsDisplayed()
.assertRangeInfoEquals(ProgressBarRangeInfo(current = 0.6f, range = 0f..1f))
composeTestRule.onNode(
hasText("Plan ${type.levels[1]} hours of your time today")
.and(hasParent(hasTestTag(tag)))
).assertExists()
}
@Test
fun maxProgress(){
val max = type.levels.last()
composeTestRule.setContent {
AchievementCard(data = type, parameter = max)
}
composeTestRule.onNodeWithTag("${tag}_progress")
.assertIsDisplayed()
.assertRangeInfoEquals(ProgressBarRangeInfo(current = 1.0f, range = 0f..1f))
composeTestRule.onNode(
hasText("You have max level, you achieve:${type.description(max)}")
.and(hasParent(hasTestTag(tag)))
).assertExists()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import org.hse.smartcalendar.data.WorkManagerHolder
import org.hse.smartcalendar.notification.ReminderViewModel
import org.hse.smartcalendar.notification.ReminderViewModelFactory
import org.hse.smartcalendar.view.model.ReminderViewModel
import org.hse.smartcalendar.view.model.ReminderViewModelFactory
import org.hse.smartcalendar.ui.screens.StatisticsScreen
import org.hse.smartcalendar.ui.task.DailyTasksList
import org.hse.smartcalendar.ui.task.TaskEditWindow
Expand Down Expand Up @@ -74,7 +74,9 @@ fun ListNavigation(
listViewModel.removeDailyTask(task)

}, onCancel = {},
taskEditViewModel = taskEditViewModel, navController = navController
taskEditViewModel = taskEditViewModel,
navController = navController,
reminderModel = reminderModel
)
}
composable(route = Screens.SETTINGS.route) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WorkManagerHolder.init(this)
val statisticsModel: StatisticsViewModel = StatisticsViewModel()
val statisticsModel = StatisticsViewModel()
val listModel = ListViewModel(StatisticsManager(statisticsModel))
val editModel = TaskEditViewModel(listModel)
enableEdgeToEdge()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class DailySchedule (val date : LocalDate = Clock.System.now()

fun setCompletionById(id: UUID, status: Boolean): Boolean {
dailyTasksList.forEach { task ->
if (task.getId() == id && task.isComplete()!=status) {
if (task.getId() == id && task.isComplete()!=status) {//т.е. у нас complete поэтому не меняем
task.setCompletion(status)
return true
}
Expand Down
39 changes: 22 additions & 17 deletions app/src/main/java/org/hse/smartcalendar/data/TotalTaskTypes.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.hse.smartcalendar.data

import org.hse.smartcalendar.utility.TimePeriod
import org.hse.smartcalendar.view.model.AbstractStatisticsViewModel.Companion.getPercent
import org.hse.smartcalendar.view.model.state.TimePeriod
import org.hse.smartcalendar.view.model.StatisticsViewModel.Companion.getPercent

class TotalTimeTaskTypes(common: Long, work: Long, study: Long, fitness: Long){
val All: TimePeriod = TimePeriod(work+study+common+fitness)
Expand All @@ -19,6 +19,14 @@ class TotalTimeTaskTypes(common: Long, work: Long, study: Long, fitness: Long){
private set
var WorkPercent: Float = getPercent(work, totalMinutes)
private set
fun getPercentByType(type: DailyTaskType): Float {
return when (type) {
DailyTaskType.COMMON -> CommonPercent
DailyTaskType.FITNESS -> FitnessPercent
DailyTaskType.WORK -> WorkPercent
DailyTaskType.STUDIES -> StudyPercent
}
}
fun completeTask(task: DailyTask, isComplete: Boolean){
val taskMinutesLength = task.getMinutesLength().toLong()
when(isComplete){
Expand All @@ -28,21 +36,18 @@ class TotalTimeTaskTypes(common: Long, work: Long, study: Long, fitness: Long){
false -> totalMinutes-=taskMinutesLength
}
All.addMinutes(taskMinutesLength, isComplete)
when(task.getDailyTaskType()){
DailyTaskType.COMMON -> {Common.addMinutes(taskMinutesLength, isComplete)
CommonPercent=getPercent(Common.toMinutes(), totalMinutes)}
DailyTaskType.FITNESS -> {
Fitness.addMinutes(taskMinutesLength, isComplete)
FitnessPercent=getPercent(Fitness.toMinutes(), totalMinutes)
}
DailyTaskType.WORK -> {
Work.addMinutes(taskMinutesLength, isComplete)
WorkPercent=getPercent(Work.toMinutes(), totalMinutes)
}
DailyTaskType.STUDIES -> {
Study.addMinutes(taskMinutesLength, isComplete)
StudyPercent=getPercent(Study.toMinutes(), totalMinutes)
}
when (task.getDailyTaskType()) {
DailyTaskType.COMMON -> Common.addMinutes(taskMinutesLength, isComplete)
DailyTaskType.FITNESS -> Fitness.addMinutes(taskMinutesLength, isComplete)
DailyTaskType.WORK -> Work.addMinutes(taskMinutesLength, isComplete)
DailyTaskType.STUDIES -> Study.addMinutes(taskMinutesLength, isComplete)
}
recalculatePercents()
}
private fun recalculatePercents() {
StudyPercent = getPercent(Study.toMinutes(), totalMinutes)
CommonPercent = getPercent(Common.toMinutes(), totalMinutes)
FitnessPercent = getPercent(Fitness.toMinutes(), totalMinutes)
WorkPercent = getPercent(Work.toMinutes(), totalMinutes)
}
}
Loading
Loading