Merge branch 'development' into feed_friends
This commit is contained in:
commit
754cad20ed
47 changed files with 1441 additions and 174 deletions
|
@ -147,4 +147,4 @@ protobuf {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
74
app/src/androidTest/java/be/ugent/sel/studeez/FabTest.kt
Normal file
74
app/src/androidTest/java/be/ugent/sel/studeez/FabTest.kt
Normal file
|
@ -0,0 +1,74 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.material.FloatingActionButton
|
||||
import androidx.compose.ui.test.hasClickAction
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.common.composable.AddButtonActions
|
||||
import be.ugent.sel.studeez.common.composable.ExpandedAddButton
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class FabTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun expandFabTest() {
|
||||
var expand = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
FloatingActionButton(
|
||||
onClick = {expand = true}
|
||||
) {}
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNode(hasClickAction())
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(expand)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fabTest() {
|
||||
var task = false
|
||||
var session = false
|
||||
var friend = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
ExpandedAddButton(
|
||||
addButtonActions = AddButtonActions(
|
||||
{task = true},
|
||||
{friend = true},
|
||||
{session = true}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("Session")
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("Task")
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("Friend")
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(task)
|
||||
assert(session)
|
||||
assert(friend)
|
||||
}
|
||||
}
|
207
app/src/androidTest/java/be/ugent/sel/studeez/HomeScreenTest.kt
Normal file
207
app/src/androidTest/java/be/ugent/sel/studeez/HomeScreenTest.kt
Normal file
|
@ -0,0 +1,207 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithContentDescription
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
|
||||
import be.ugent.sel.studeez.common.composable.feed.FeedUiState
|
||||
import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions
|
||||
import be.ugent.sel.studeez.data.local.models.FeedEntry
|
||||
import be.ugent.sel.studeez.screens.home.HomeScreen
|
||||
import org.junit.Assert
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class HomeScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun homeScreenTest() {
|
||||
var continueTask = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
HomeScreen(
|
||||
drawerActions = DrawerActions({}, {}, {}, {}, {}),
|
||||
navigationBarActions = NavigationBarActions({false}, {}, {}, {}, {}, {}, {}, {}),
|
||||
feedUiState = FeedUiState.Succes(mapOf(
|
||||
"08 May 2023" to listOf(
|
||||
FeedEntry(
|
||||
argb_color = 0xFFABD200,
|
||||
subJectName = "Test Subject",
|
||||
taskName = "Test Task",
|
||||
totalStudyTime = 600,
|
||||
)
|
||||
)
|
||||
)),
|
||||
continueTask = {_, _ -> continueTask = true },
|
||||
onEmptyFeedHelp = {},
|
||||
onViewFriendsClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
"continue",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
Assert.assertTrue(continueTask)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun drawerTest() {
|
||||
var homebuttontest = false
|
||||
var timersbuttontest = false
|
||||
var settingsbuttontest = false
|
||||
var logoutbuttontest = false
|
||||
var aboutbuttontest = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
HomeScreen(
|
||||
drawerActions = DrawerActions(
|
||||
{homebuttontest = true},
|
||||
{timersbuttontest = true},
|
||||
{settingsbuttontest = true},
|
||||
{logoutbuttontest = true},
|
||||
{aboutbuttontest = true}
|
||||
),
|
||||
navigationBarActions = NavigationBarActions({false}, {}, {}, {}, {}, {}, {}, {}),
|
||||
feedUiState = FeedUiState.Succes(mapOf()),
|
||||
continueTask = {_, _ -> },
|
||||
onEmptyFeedHelp = {},
|
||||
onViewFriendsClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText(
|
||||
"home",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)[2] // Third node has the button
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
"timer",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
"settings",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
"log out",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
"about",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
Assert.assertTrue(homebuttontest)
|
||||
Assert.assertTrue(timersbuttontest)
|
||||
Assert.assertTrue(settingsbuttontest)
|
||||
Assert.assertTrue(logoutbuttontest)
|
||||
Assert.assertTrue(aboutbuttontest)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun navigationbarTest() {
|
||||
var hometest = false
|
||||
var tasktest = false
|
||||
var sessiontest = false
|
||||
var profiletest = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
HomeScreen(
|
||||
drawerActions = DrawerActions({}, {}, {}, {}, {}),
|
||||
navigationBarActions = NavigationBarActions(
|
||||
{false},
|
||||
{hometest = true},
|
||||
{tasktest = true},
|
||||
{sessiontest = true},
|
||||
{profiletest = true},
|
||||
{}, {}, {}
|
||||
),
|
||||
feedUiState = FeedUiState.Succes(mapOf()),
|
||||
continueTask = {_, _ -> },
|
||||
onEmptyFeedHelp = {},
|
||||
onViewFriendsClick = {},
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithContentDescription(
|
||||
"Home",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)[0] // Third node has the button
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
"tasks",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
"session",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
"profile",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
Assert.assertTrue(hometest)
|
||||
Assert.assertTrue(tasktest)
|
||||
Assert.assertTrue(sessiontest)
|
||||
Assert.assertTrue(profiletest)
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ import org.junit.Assert.*
|
|||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
class InstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
|
@ -0,0 +1,68 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.screens.log_in.LoginScreen
|
||||
import be.ugent.sel.studeez.screens.log_in.LoginScreenActions
|
||||
import be.ugent.sel.studeez.screens.log_in.LoginUiState
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class LoginScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun loginScreenTest() {
|
||||
var login = false
|
||||
var signup = false
|
||||
var forgot_password = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
LoginScreen(
|
||||
uiState = LoginUiState(),
|
||||
loginScreenActions = LoginScreenActions(
|
||||
{}, {},
|
||||
{signup = true},
|
||||
{login = true},
|
||||
{forgot_password = true}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText(
|
||||
text = "Sign in",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)[0] // The first object is the button
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "Forgot",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "Sign up",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(signup)
|
||||
assert(login)
|
||||
assert(forgot_password)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.screens.profile.edit_profile.EditProfileActions
|
||||
import be.ugent.sel.studeez.screens.profile.edit_profile.EditProfileScreen
|
||||
import be.ugent.sel.studeez.screens.profile.edit_profile.ProfileEditUiState
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class ProfileEditScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun profileEditScreenTest() {
|
||||
var edit_save = false
|
||||
var goback = false
|
||||
var delete_click = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
EditProfileScreen(
|
||||
goBack = {goback = true},
|
||||
uiState = ProfileEditUiState(),
|
||||
editProfileActions = EditProfileActions(
|
||||
onUserNameChange = {},
|
||||
onBiographyChange = {},
|
||||
onSaveClick = {edit_save = true},
|
||||
onDeleteClick = { delete_click = true },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "save",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "delete",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "go back",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(edit_save)
|
||||
assert(goback)
|
||||
assert(delete_click)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
|
||||
import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions
|
||||
import be.ugent.sel.studeez.screens.profile.ProfileActions
|
||||
import be.ugent.sel.studeez.screens.profile.ProfileScreen
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class ProfileScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun profileScreenTest() {
|
||||
var edit = false
|
||||
var view_friends = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
ProfileScreen(
|
||||
profileActions = ProfileActions(
|
||||
getUsername = {null},
|
||||
onEditProfileClick = {edit = true},
|
||||
getBiography = {null},
|
||||
getAmountOfFriends = { flowOf(0) },
|
||||
onViewFriendsClick = {view_friends = true}
|
||||
),
|
||||
drawerActions = DrawerActions({}, {}, {}, {}, {}),
|
||||
navigationBarActions = NavigationBarActions({ false }, {}, {}, {}, {}, {}, {}, {})
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "edit profile",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "friends",
|
||||
substring = true,
|
||||
ignoreCase = true,
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(edit)
|
||||
assert(view_friends)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.data.local.models.SessionReport
|
||||
import be.ugent.sel.studeez.screens.session_recap.SessionRecapActions
|
||||
import be.ugent.sel.studeez.screens.session_recap.SessionRecapScreen
|
||||
import com.google.firebase.Timestamp
|
||||
import org.junit.Assert
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
|
||||
class SessionRecapScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun sessionRecapTest() {
|
||||
var saveCalled = false
|
||||
var discardCalled = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SessionRecapScreen(
|
||||
Modifier,
|
||||
SessionRecapActions(
|
||||
{
|
||||
SessionReport(
|
||||
"",
|
||||
0,
|
||||
Timestamp(0, 0),
|
||||
"")
|
||||
},
|
||||
{ saveCalled = true },
|
||||
{ discardCalled = true }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
"You studied",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
"save",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
"discard",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
Assert.assertTrue(saveCalled)
|
||||
Assert.assertTrue(discardCalled)
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.screens.sign_up.SignUpActions
|
||||
import be.ugent.sel.studeez.screens.sign_up.SignUpScreen
|
||||
import be.ugent.sel.studeez.screens.sign_up.SignUpUiState
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class SignUpScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun signupScreenTest() {
|
||||
var create = false
|
||||
var login = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SignUpScreen(
|
||||
uiState = SignUpUiState(),
|
||||
signUpActions = SignUpActions({}, {}, {}, {}, {create = true}, {login = true})
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "log in",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText(
|
||||
text = "Create account",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)[0] // First node has the button
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(login)
|
||||
assert(create)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.screens.splash.SplashScreen
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class SplashScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun splashScreenTest() {
|
||||
var tryAgain = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SplashScreen(
|
||||
Modifier,
|
||||
{tryAgain = true},
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onAllNodesWithText(
|
||||
text = "try again",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)[1] // Second node is the button
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(tryAgain)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.common.composable.DeleteButton
|
||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
|
||||
import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions
|
||||
import be.ugent.sel.studeez.data.local.models.task.Subject
|
||||
import be.ugent.sel.studeez.screens.subjects.SubjectScreen
|
||||
import be.ugent.sel.studeez.screens.subjects.SubjectUiState
|
||||
import be.ugent.sel.studeez.screens.subjects.form.SubjectForm
|
||||
import be.ugent.sel.studeez.screens.subjects.form.SubjectFormUiState
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class SubjectScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun addSubjectScreenTest() {
|
||||
var confirm = false
|
||||
var goback = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SubjectForm(
|
||||
title = R.string.new_subject,
|
||||
goBack = {goback = true},
|
||||
uiState = SubjectFormUiState(),
|
||||
onConfirm = {confirm = true},
|
||||
onNameChange = {},
|
||||
onColorChange = {},
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "confirm",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "go back",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(confirm)
|
||||
assert(goback)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun editSubjectScreenTest() {
|
||||
var confirm = false
|
||||
var delete = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SubjectForm(
|
||||
title = R.string.edit_subject,
|
||||
goBack = {},
|
||||
uiState = SubjectFormUiState(
|
||||
name = "Test Subject",
|
||||
),
|
||||
onConfirm = {confirm = true},
|
||||
onNameChange = {},
|
||||
onColorChange = {},
|
||||
)
|
||||
DeleteButton(text = R.string.delete_subject) {
|
||||
delete = true
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "confirm",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "delete",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(confirm)
|
||||
assert(delete)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun subjectScreenTest() {
|
||||
var view = false
|
||||
var add = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
SubjectScreen(
|
||||
drawerActions = DrawerActions({}, {}, {}, {}, {}),
|
||||
navigationBarActions = NavigationBarActions({false}, {}, {}, {}, {}, {}, {}, {}),
|
||||
onAddSubject = { add = true },
|
||||
onViewSubject = { view = true },
|
||||
getStudyTime = { flowOf() },
|
||||
getCompletedTaskCount = { flowOf() },
|
||||
getTaskCount = { flowOf() },
|
||||
uiState = SubjectUiState.Succes(
|
||||
listOf(
|
||||
Subject(
|
||||
id = "",
|
||||
name = "Test Subject",
|
||||
argb_color = 0xFFFFD200,
|
||||
archived = false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "view",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "new subject",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(add)
|
||||
assert(view)
|
||||
}
|
||||
}
|
160
app/src/androidTest/java/be/ugent/sel/studeez/TaskScreenTest.kt
Normal file
160
app/src/androidTest/java/be/ugent/sel/studeez/TaskScreenTest.kt
Normal file
|
@ -0,0 +1,160 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.common.composable.DeleteButton
|
||||
import be.ugent.sel.studeez.data.local.models.task.Subject
|
||||
import be.ugent.sel.studeez.data.local.models.task.Task
|
||||
import be.ugent.sel.studeez.screens.tasks.TaskActions
|
||||
import be.ugent.sel.studeez.screens.tasks.TaskScreen
|
||||
import be.ugent.sel.studeez.screens.tasks.form.TaskForm
|
||||
import be.ugent.sel.studeez.screens.tasks.form.TaskFormUiState
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class TaskScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun addTaskScreenTest() {
|
||||
var confirm = false
|
||||
var goback = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
TaskForm(
|
||||
title = R.string.new_task,
|
||||
goBack = {goback = true},
|
||||
uiState = TaskFormUiState(),
|
||||
onConfirm = {confirm = true},
|
||||
onNameChange = {},
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "confirm",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "go back",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(confirm)
|
||||
assert(goback)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun editTaskScreenTest() {
|
||||
var confirm = false
|
||||
var delete = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
TaskForm(
|
||||
title = R.string.edit_task,
|
||||
goBack = {},
|
||||
uiState = TaskFormUiState(
|
||||
name = "Test Task",
|
||||
),
|
||||
onConfirm = {confirm = true},
|
||||
onNameChange = {},
|
||||
) {
|
||||
DeleteButton(text = R.string.delete_task) {
|
||||
delete = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "confirm",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "delete",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(confirm)
|
||||
assert(delete)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun taskScreenTest() {
|
||||
var add = false
|
||||
var edit = false
|
||||
var start = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
TaskScreen(
|
||||
goBack = {},
|
||||
taskActions = TaskActions(
|
||||
{add = true},
|
||||
{ Subject(name = "Test Subject") },
|
||||
{ flowOf(listOf(Task())) },
|
||||
{ _, _ -> run {} },
|
||||
{edit = true},
|
||||
{start = true},
|
||||
{},
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription(
|
||||
label = "edit",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "new",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "start",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(add)
|
||||
assert(edit)
|
||||
assert(start)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.EndlessTimerInfo
|
||||
import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewActions
|
||||
import be.ugent.sel.studeez.screens.timer_overview.TimerOverviewScreen
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class TimerOverviewScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun timerOverviewScreenTest() {
|
||||
var add = false
|
||||
var edit = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
TimerOverviewScreen(
|
||||
timerOverviewActions = TimerOverviewActions(
|
||||
{ flowOf(listOf(EndlessTimerInfo("", ""))) },
|
||||
{ listOf() },
|
||||
{edit = true},
|
||||
{add = true}
|
||||
),
|
||||
drawerActions = DrawerActions({}, {}, {}, {}, {})
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "add",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "edit",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(add)
|
||||
assert(edit)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package be.ugent.sel.studeez
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionActions
|
||||
import be.ugent.sel.studeez.screens.timer_selection.TimerSelectionScreen
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class TimerSelectionScreenTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun timerOverviewScreenTest() {
|
||||
var start = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
TimerSelectionScreen(
|
||||
timerSelectionActions = TimerSelectionActions({ flowOf()}, {start = true}, 0),
|
||||
popUp = {}
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText(
|
||||
text = "start",
|
||||
substring = true,
|
||||
ignoreCase = true
|
||||
)
|
||||
.assertExists()
|
||||
.performClick()
|
||||
|
||||
assert(start)
|
||||
}
|
||||
}
|
|
@ -227,12 +227,14 @@ fun SearchField(
|
|||
onValueChange: (String) -> Unit,
|
||||
onSubmit: () -> Unit,
|
||||
@StringRes label: Int,
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
label = { Text(text = stringResource(id = label)) },
|
||||
trailingIcon = {
|
||||
IconButton(onClick = onSubmit) {
|
||||
|
|
|
@ -81,7 +81,7 @@ fun FeedWithElements(
|
|||
Text(
|
||||
text = "${HoursMinutesSeconds(totalDayStudyTime)}",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
feedEntries.forEach { feedEntry ->
|
||||
|
|
|
@ -56,7 +56,7 @@ fun FeedEntry(
|
|||
) {
|
||||
Text(
|
||||
text = feedEntry.subJectName,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontWeight = FontWeight.Medium,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
|
|
|
@ -5,6 +5,9 @@ import be.ugent.sel.studeez.domain.LogService
|
|||
import be.ugent.sel.studeez.navigation.StudeezDestinations.FRIENDS_FEED
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.HOME_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.PROFILE_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.SEARCH_FRIENDS_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.SELECT_SUBJECT
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.SESSIONS_SCREEN
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations.SUBJECT_SCREEN
|
||||
import be.ugent.sel.studeez.screens.StudeezViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
@ -33,13 +36,11 @@ class NavigationBarViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onAddTaskClick(open: (String) -> Unit) {
|
||||
// TODO open(CREATE_TASK_SCREEN)
|
||||
SnackbarManager.showMessage(AppText.create_task_not_possible_yet) // TODO Remove
|
||||
open(SELECT_SUBJECT)
|
||||
}
|
||||
|
||||
fun onAddFriendClick(open: (String) -> Unit) {
|
||||
// TODO open(SEARCH_FRIENDS_SCREEN)
|
||||
SnackbarManager.showMessage(AppText.add_friend_not_possible_yet) // TODO Remove
|
||||
open(SEARCH_FRIENDS_SCREEN)
|
||||
}
|
||||
|
||||
fun onAddSessionClick(open: (String) -> Unit) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.*
|
|||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.List
|
||||
|
@ -30,10 +31,10 @@ import be.ugent.sel.studeez.R.string as AppText
|
|||
@Composable
|
||||
fun SubjectEntry(
|
||||
subject: Subject,
|
||||
onViewSubject: () -> Unit,
|
||||
getTaskCount: () -> Flow<Int>,
|
||||
getCompletedTaskCount: () -> Flow<Int>,
|
||||
getStudyTime: () -> Flow<Int>,
|
||||
selectButton: @Composable (RowScope) -> Unit,
|
||||
) {
|
||||
val studytime by getStudyTime().collectAsState(initial = 0)
|
||||
val taskCount by getTaskCount().collectAsState(initial = 0)
|
||||
|
@ -65,16 +66,17 @@ fun SubjectEntry(
|
|||
) {
|
||||
Text(
|
||||
text = subject.name,
|
||||
fontWeight = FontWeight.Bold,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = HoursMinutesSeconds(studytime).toString(),
|
||||
color = MaterialTheme.colors.onBackground.copy(alpha = 0.6f)
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
@ -82,21 +84,18 @@ fun SubjectEntry(
|
|||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.List,
|
||||
contentDescription = stringResource(id = AppText.tasks)
|
||||
contentDescription = stringResource(id = AppText.tasks),
|
||||
tint = MaterialTheme.colors.onBackground.copy(alpha = 0.6f)
|
||||
)
|
||||
Text(
|
||||
text = "${completedTaskCount}/${taskCount}",
|
||||
color = MaterialTheme.colors.onBackground.copy(alpha = 0.6f)
|
||||
)
|
||||
Text(text = "${completedTaskCount}/${taskCount}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
StealthButton(
|
||||
text = AppText.view_tasks,
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp, end = 5.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
onViewSubject()
|
||||
}
|
||||
selectButton(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,11 +108,16 @@ fun SubjectEntryPreview() {
|
|||
name = "Test Subject",
|
||||
argb_color = 0xFFFFD200,
|
||||
),
|
||||
onViewSubject = {},
|
||||
getTaskCount = { flowOf() },
|
||||
getCompletedTaskCount = { flowOf() },
|
||||
getStudyTime = { flowOf() },
|
||||
)
|
||||
) {
|
||||
StealthButton(
|
||||
text = AppText.view_tasks,
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp, end = 5.dp)
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
|
@ -124,9 +128,8 @@ fun OverflowSubjectEntryPreview() {
|
|||
name = "Testttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
|
||||
argb_color = 0xFFFFD200,
|
||||
),
|
||||
onViewSubject = {},
|
||||
getTaskCount = { flowOf() },
|
||||
getCompletedTaskCount = { flowOf() },
|
||||
getStudyTime = { flowOf() },
|
||||
)
|
||||
) {}
|
||||
}
|
|
@ -5,6 +5,7 @@ import be.ugent.sel.studeez.data.local.models.task.Subject
|
|||
import be.ugent.sel.studeez.data.local.models.task.Task
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||
import be.ugent.sel.studeez.domain.UserDAO
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -42,4 +43,11 @@ class SelectedSubject @Inject constructor() : SelectedState<Subject>() {
|
|||
@Singleton
|
||||
class SelectedTimerInfo @Inject constructor() : SelectedState<TimerInfo>() {
|
||||
override lateinit var value: TimerInfo
|
||||
}
|
||||
|
||||
@Singleton
|
||||
class SelectedUserId @Inject constructor(
|
||||
userDAO: UserDAO
|
||||
): SelectedState<String>() {
|
||||
override var value: String = userDAO.getCurrentUserId()
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package be.ugent.sel.studeez.data.local.models.task
|
||||
|
||||
import com.google.firebase.firestore.DocumentId
|
||||
import com.google.firebase.firestore.Exclude
|
||||
|
||||
data class Subject(
|
||||
@DocumentId val id: String = "",
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package be.ugent.sel.studeez.domain.implementation
|
||||
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
|
||||
import be.ugent.sel.studeez.data.local.models.Friendship
|
||||
import be.ugent.sel.studeez.data.remote.FirebaseFriendship.ACCEPTED
|
||||
import be.ugent.sel.studeez.data.remote.FirebaseFriendship.FRIENDSSINCE
|
||||
import be.ugent.sel.studeez.data.remote.FirebaseFriendship.FRIENDID
|
||||
import be.ugent.sel.studeez.data.remote.FirebaseFriendship.FRIENDSSINCE
|
||||
import be.ugent.sel.studeez.domain.AccountDAO
|
||||
import be.ugent.sel.studeez.domain.FriendshipDAO
|
||||
import be.ugent.sel.studeez.domain.implementation.FirebaseCollections.FRIENDS_COLLECTION
|
||||
|
@ -18,6 +17,7 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
@ -75,24 +75,40 @@ class FirebaseFriendshipDAO @Inject constructor(
|
|||
val currentUserId: String = auth.currentUserId
|
||||
val otherUserId: String = id
|
||||
|
||||
// Add entry to current user
|
||||
currentUserDocument()
|
||||
.collection(FRIENDS_COLLECTION)
|
||||
.add(mapOf(
|
||||
FRIENDID to otherUserId,
|
||||
ACCEPTED to true, // TODO Make it not automatically accepted.
|
||||
FRIENDSSINCE to Timestamp.now()
|
||||
))
|
||||
|
||||
// Add entry to other user
|
||||
// Check if the friendship already exists for the logged in user
|
||||
var allowed = false
|
||||
firestore.collection(USER_COLLECTION)
|
||||
.document(otherUserId)
|
||||
.document(currentUserId)
|
||||
.collection(FRIENDS_COLLECTION)
|
||||
.add(mapOf(
|
||||
FRIENDID to currentUserId,
|
||||
ACCEPTED to true, // TODO Make it not automatically accepted.
|
||||
FRIENDSSINCE to Timestamp.now()
|
||||
))
|
||||
.whereEqualTo(FRIENDID, otherUserId)
|
||||
.get()
|
||||
.addOnSuccessListener {
|
||||
allowed = it.documents.isEmpty()
|
||||
|
||||
if (allowed) {
|
||||
// Add entry to current user
|
||||
currentUserDocument()
|
||||
.collection(FRIENDS_COLLECTION)
|
||||
.add(mapOf(
|
||||
FRIENDID to otherUserId,
|
||||
ACCEPTED to true, // TODO Make it not automatically accepted.
|
||||
FRIENDSSINCE to Timestamp.now()
|
||||
))
|
||||
|
||||
// Add entry to other user
|
||||
firestore.collection(USER_COLLECTION)
|
||||
.document(otherUserId)
|
||||
.collection(FRIENDS_COLLECTION)
|
||||
.add(mapOf(
|
||||
FRIENDID to currentUserId,
|
||||
ACCEPTED to true, // TODO Make it not automatically accepted.
|
||||
FRIENDSSINCE to Timestamp.now()
|
||||
))
|
||||
}
|
||||
}.addOnSuccessListener {
|
||||
val message = if (allowed) AppText.success else AppText.already_friend
|
||||
SnackbarManager.showMessage(message)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -94,4 +94,4 @@ class FirebaseSubjectDAO @Inject constructor(
|
|||
|
||||
fun Query.subjectNotArchived(): Query =
|
||||
this.whereEqualTo(SubjectDocument.archived, false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ object StudeezDestinations {
|
|||
const val EDIT_SUBJECT_FORM = "edit_subject"
|
||||
const val TASKS_SCREEN = "tasks"
|
||||
const val ADD_TASK_FORM = "add_task"
|
||||
const val SELECT_SUBJECT = "select_subject"
|
||||
const val EDIT_TASK_FORM = "edit_task"
|
||||
|
||||
// Friends flow
|
||||
|
|
|
@ -31,6 +31,7 @@ import be.ugent.sel.studeez.screens.splash.SplashRoute
|
|||
import be.ugent.sel.studeez.screens.subjects.SubjectRoute
|
||||
import be.ugent.sel.studeez.screens.subjects.form.SubjectCreateRoute
|
||||
import be.ugent.sel.studeez.screens.subjects.form.SubjectEditRoute
|
||||
import be.ugent.sel.studeez.screens.subjects.select.SubjectSelectionRoute
|
||||
import be.ugent.sel.studeez.screens.tasks.TaskRoute
|
||||
import be.ugent.sel.studeez.screens.tasks.form.TaskCreateRoute
|
||||
import be.ugent.sel.studeez.screens.tasks.form.TaskEditRoute
|
||||
|
@ -69,7 +70,7 @@ fun StudeezNavGraph(
|
|||
// NavBar
|
||||
composable(StudeezDestinations.HOME_SCREEN) {
|
||||
HomeRoute(
|
||||
open,
|
||||
open = open,
|
||||
drawerActions = drawerActions,
|
||||
navigationBarActions = navigationBarActions,
|
||||
feedViewModel = hiltViewModel(),
|
||||
|
@ -86,6 +87,14 @@ fun StudeezNavGraph(
|
|||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.SELECT_SUBJECT) {
|
||||
SubjectSelectionRoute(
|
||||
open = { openAndPopUp(it, StudeezDestinations.SELECT_SUBJECT) },
|
||||
goBack = goBack,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
}
|
||||
|
||||
composable(StudeezDestinations.ADD_SUBJECT_FORM) {
|
||||
SubjectCreateRoute(
|
||||
goBack = goBack,
|
||||
|
@ -104,7 +113,7 @@ fun StudeezNavGraph(
|
|||
|
||||
composable(StudeezDestinations.TASKS_SCREEN) {
|
||||
TaskRoute(
|
||||
goBack = goBack,
|
||||
goBack = { openAndPopUp(StudeezDestinations.SUBJECT_SCREEN, StudeezDestinations.TASKS_SCREEN) },
|
||||
open = open,
|
||||
viewModel = hiltViewModel(),
|
||||
)
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
package be.ugent.sel.studeez.screens.friends.friends_overview
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -23,7 +22,6 @@ import androidx.compose.ui.unit.sp
|
|||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.common.composable.BasicButton
|
||||
import be.ugent.sel.studeez.common.composable.ProfilePicture
|
||||
import be.ugent.sel.studeez.common.composable.SearchField
|
||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerEntry
|
||||
import be.ugent.sel.studeez.common.ext.basicButton
|
||||
import be.ugent.sel.studeez.data.local.models.Friendship
|
||||
|
@ -89,13 +87,32 @@ fun FriendsOverviewScreen(
|
|||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
// TODO Link to each other
|
||||
SearchField(
|
||||
value = uiState.queryString,
|
||||
onValueChange = friendsOverviewActions.onQueryStringChange,
|
||||
onSubmit = friendsOverviewActions.onSubmit,
|
||||
label = AppText.search_friends
|
||||
)
|
||||
// TODO Make search field
|
||||
// SearchField(
|
||||
// value = uiState.queryString,
|
||||
// onValueChange = friendsOverviewActions.onQueryStringChange,
|
||||
// onSubmit = friendsOverviewActions.onSubmit,
|
||||
// label = AppText.search_friends,
|
||||
// enabled = false
|
||||
// )
|
||||
IconButton(
|
||||
onClick = friendsOverviewActions.onSubmit,
|
||||
// modifier = Modifier.background(
|
||||
// color = MaterialTheme.colors.background
|
||||
// ),
|
||||
) {
|
||||
Row {
|
||||
Text(
|
||||
text = stringResource(id = AppText.click_search_friends),
|
||||
color = MaterialTheme.colors.onPrimary
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Default.Search,
|
||||
contentDescription = stringResource(AppText.search_friends),
|
||||
tint = MaterialTheme.colors.onPrimary
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = popUp) {
|
||||
|
@ -162,49 +179,52 @@ fun FriendsEntry(
|
|||
viewProfile: (String) -> Unit,
|
||||
removeFriend: (Friendship) -> Unit
|
||||
) {
|
||||
Row (
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 15.dp, vertical = 7.dp),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
) {
|
||||
ProfilePicture()
|
||||
}
|
||||
|
||||
Box (
|
||||
Card {
|
||||
Row (
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 15.dp, vertical = 7.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(15.dp)
|
||||
) {
|
||||
Column (
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
) {
|
||||
Text(
|
||||
text = user.username,
|
||||
fontSize = 16.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Text(
|
||||
text = "${resources().getString(AppText.app_name)} ${resources().getString(AppText.friend)}",
|
||||
fontSize = 14.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
ProfilePicture()
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.CenterEnd
|
||||
Box (
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
FriendsOverviewDropDown(
|
||||
friendship = friendship,
|
||||
viewProfile = viewProfile,
|
||||
removeFriend = removeFriend
|
||||
)
|
||||
Column (
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp)
|
||||
) {
|
||||
Text(
|
||||
text = user.username,
|
||||
fontSize = 16.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Text(
|
||||
text = "${resources().getString(AppText.app_name)} ${resources().getString(AppText.friend)}",
|
||||
fontSize = 14.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.CenterEnd
|
||||
) {
|
||||
FriendsOverviewDropDown(
|
||||
friendship = friendship,
|
||||
viewProfile = viewProfile,
|
||||
removeFriend = removeFriend
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package be.ugent.sel.studeez.screens.friends.friends_overview
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import be.ugent.sel.studeez.data.SelectedUserId
|
||||
import be.ugent.sel.studeez.data.local.models.Friendship
|
||||
import be.ugent.sel.studeez.data.local.models.User
|
||||
import be.ugent.sel.studeez.domain.FriendshipDAO
|
||||
|
@ -8,7 +9,6 @@ import be.ugent.sel.studeez.domain.LogService
|
|||
import be.ugent.sel.studeez.domain.UserDAO
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
|
||||
import be.ugent.sel.studeez.screens.StudeezViewModel
|
||||
import be.ugent.sel.studeez.screens.profile.public_profile.SelectedProfileState
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
@ -19,12 +19,12 @@ import javax.inject.Inject
|
|||
class FriendsOverviewViewModel @Inject constructor(
|
||||
private val userDAO: UserDAO,
|
||||
private val friendshipDAO: FriendshipDAO,
|
||||
private val selectedProfileState: SelectedProfileState,
|
||||
private val selectedUserIdState: SelectedUserId,
|
||||
logService: LogService
|
||||
) : StudeezViewModel(logService) {
|
||||
|
||||
var uiState = mutableStateOf(FriendsOverviewUiState(
|
||||
userId = selectedProfileState.selectedUserId
|
||||
userId = selectedUserIdState.value
|
||||
))
|
||||
private set
|
||||
|
||||
|
@ -63,7 +63,7 @@ class FriendsOverviewViewModel @Inject constructor(
|
|||
userId: String,
|
||||
open: (String) -> Unit
|
||||
) {
|
||||
selectedProfileState.selectedUserId = userId
|
||||
selectedUserIdState.value = userId
|
||||
open(StudeezDestinations.PUBLIC_PROFILE_SCREEN)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import androidx.compose.material.*
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Person
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -82,14 +83,16 @@ fun SearchFriendsScreen(
|
|||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
SearchField(
|
||||
value = query,
|
||||
onValueChange = { newValue ->
|
||||
searchFriendsActions.onQueryStringChange(newValue)
|
||||
query = newValue
|
||||
},
|
||||
onSubmit = { },
|
||||
label = AppText.search_friends
|
||||
// TODO Make search field
|
||||
// SearchField(
|
||||
// value = uiState.queryString,
|
||||
// onValueChange = friendsOverviewActions.onQueryStringChange,
|
||||
// onSubmit = friendsOverviewActions.onSubmit,
|
||||
// label = AppText.search_friends,
|
||||
// enabled = false
|
||||
// )
|
||||
Text(
|
||||
text = stringResource(id = AppText.searching_friends)
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
package be.ugent.sel.studeez.screens.friends.friends_search
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import be.ugent.sel.studeez.data.SelectedUserId
|
||||
import be.ugent.sel.studeez.data.local.models.User
|
||||
import be.ugent.sel.studeez.data.remote.FirebaseUser
|
||||
import be.ugent.sel.studeez.domain.LogService
|
||||
import be.ugent.sel.studeez.domain.UserDAO
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
|
||||
import be.ugent.sel.studeez.screens.StudeezViewModel
|
||||
import be.ugent.sel.studeez.screens.profile.public_profile.SelectedProfileState
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class SearchFriendsViewModel @Inject constructor(
|
||||
private val userDAO: UserDAO,
|
||||
private val selectedProfileState: SelectedProfileState,
|
||||
private val selectedProfileState: SelectedUserId,
|
||||
logService: LogService
|
||||
): StudeezViewModel(logService) {
|
||||
|
||||
|
@ -49,8 +49,8 @@ class SearchFriendsViewModel @Inject constructor(
|
|||
*/
|
||||
fun getAllUsers(): Flow<List<User>> {
|
||||
return userDAO.getAllUsers()
|
||||
.filter { users ->
|
||||
users.any { user ->
|
||||
.map { users ->
|
||||
users.filter { user ->
|
||||
user.id != userDAO.getCurrentUserId()
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ class SearchFriendsViewModel @Inject constructor(
|
|||
userId: String,
|
||||
open: (String) -> Unit
|
||||
) {
|
||||
selectedProfileState.selectedUserId = userId
|
||||
selectedProfileState.value = userId
|
||||
open(StudeezDestinations.PUBLIC_PROFILE_SCREEN)
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ import be.ugent.sel.studeez.R
|
|||
import be.ugent.sel.studeez.common.composable.Headline
|
||||
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerEntry
|
||||
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
|
||||
import be.ugent.sel.studeez.data.local.models.User
|
||||
import be.ugent.sel.studeez.resources
|
||||
import be.ugent.sel.studeez.screens.profile.AmountOfFriendsButton
|
||||
|
@ -30,7 +31,7 @@ data class PublicProfileActions(
|
|||
val getUserDetails: () -> Flow<User>,
|
||||
val getAmountOfFriends: () -> Flow<Int>,
|
||||
val onViewFriendsClick: () -> Unit,
|
||||
val sendFriendRequest: () -> Boolean
|
||||
val sendFriendRequest: () -> Unit
|
||||
)
|
||||
|
||||
fun getPublicProfileActions(
|
||||
|
@ -43,9 +44,11 @@ fun getPublicProfileActions(
|
|||
userId = viewModel.uiState.value.userId
|
||||
) },
|
||||
onViewFriendsClick = { viewModel.onViewFriendsClick(open) },
|
||||
sendFriendRequest = { viewModel.sendFriendRequest(
|
||||
userId = viewModel.uiState.value.userId
|
||||
) }
|
||||
sendFriendRequest = {
|
||||
viewModel.sendFriendRequest(
|
||||
userId = viewModel.uiState.value.userId
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -129,7 +132,7 @@ fun PublicProfilePreview() {
|
|||
},
|
||||
getAmountOfFriends = { flowOf(113) },
|
||||
onViewFriendsClick = {},
|
||||
sendFriendRequest = { true }
|
||||
sendFriendRequest = {}
|
||||
),
|
||||
popUp = {}
|
||||
)
|
||||
|
@ -138,7 +141,7 @@ fun PublicProfilePreview() {
|
|||
|
||||
@Composable
|
||||
fun PublicProfileEllipsis(
|
||||
sendFriendRequest: () -> Boolean
|
||||
sendFriendRequest: () -> Unit
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
|
@ -147,8 +150,7 @@ fun PublicProfileEllipsis(
|
|||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_more_horizontal),
|
||||
contentDescription = resources().getString(AppText.view_more),
|
||||
modifier = Modifier.fillMaxSize()
|
||||
contentDescription = resources().getString(AppText.view_more)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -172,7 +174,7 @@ fun PublicProfileEllipsis(
|
|||
fun PublicProfileEllipsisPreview() {
|
||||
StudeezTheme {
|
||||
PublicProfileEllipsis(
|
||||
sendFriendRequest = { true }
|
||||
sendFriendRequest = {}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package be.ugent.sel.studeez.screens.profile.public_profile
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import be.ugent.sel.studeez.common.snackbar.SnackbarManager
|
||||
import be.ugent.sel.studeez.data.SelectedUserId
|
||||
import be.ugent.sel.studeez.data.local.models.User
|
||||
import be.ugent.sel.studeez.domain.FriendshipDAO
|
||||
import be.ugent.sel.studeez.domain.LogService
|
||||
|
@ -9,20 +11,20 @@ import be.ugent.sel.studeez.navigation.StudeezDestinations
|
|||
import be.ugent.sel.studeez.screens.StudeezViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.selects.select
|
||||
import javax.inject.Inject
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
||||
@HiltViewModel
|
||||
class PublicProfileViewModel @Inject constructor(
|
||||
private val userDAO: UserDAO,
|
||||
private val friendshipDAO: FriendshipDAO,
|
||||
selectedProfileState: SelectedProfileState,
|
||||
selectedUserIdState: SelectedUserId,
|
||||
logService: LogService
|
||||
): StudeezViewModel(logService) {
|
||||
|
||||
val uiState = mutableStateOf(
|
||||
PublicProfileUiState(
|
||||
userId = selectedProfileState.selectedUserId
|
||||
userId = selectedUserIdState.value
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -53,8 +55,8 @@ class PublicProfileViewModel @Inject constructor(
|
|||
|
||||
fun sendFriendRequest(
|
||||
userId: String
|
||||
): Boolean {
|
||||
return friendshipDAO.sendFriendshipRequest(userId)
|
||||
) {
|
||||
friendshipDAO.sendFriendshipRequest(userId)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package be.ugent.sel.studeez.screens.profile.public_profile
|
||||
|
||||
import be.ugent.sel.studeez.domain.UserDAO
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SelectedProfileState @Inject constructor(
|
||||
userDAO: UserDAO
|
||||
) {
|
||||
var selectedUserId: String = userDAO.getCurrentUserId()
|
||||
}
|
|
@ -1,10 +1,6 @@
|
|||
package be.ugent.sel.studeez.screens.session
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.media.MediaPlayer
|
||||
import android.media.RingtoneManager
|
||||
import android.net.Uri
|
||||
import kotlinx.coroutines.delay
|
||||
import javax.inject.Singleton
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
@ -14,10 +10,8 @@ object InvisibleSessionManager {
|
|||
private var viewModel: SessionViewModel? = null
|
||||
private lateinit var mediaPlayer: MediaPlayer
|
||||
|
||||
fun setParameters(viewModel: SessionViewModel, context: Context) {
|
||||
val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
this.mediaPlayer = MediaPlayer.create(context, uri)
|
||||
this.mediaPlayer.isLooping = false
|
||||
fun setParameters(viewModel: SessionViewModel, mediaPlayer: MediaPlayer) {
|
||||
this.mediaPlayer = mediaPlayer
|
||||
this.viewModel = viewModel
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package be.ugent.sel.studeez.screens.session
|
||||
|
||||
import android.media.MediaPlayer
|
||||
import android.media.RingtoneManager
|
||||
import android.net.Uri
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalTimer
|
||||
|
@ -28,8 +31,11 @@ fun SessionRoute(
|
|||
openAndPopUp: (String, String) -> Unit,
|
||||
viewModel: SessionViewModel,
|
||||
) {
|
||||
val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
||||
val mediaPlayer = MediaPlayer.create(LocalContext.current, uri)
|
||||
mediaPlayer.isLooping = false
|
||||
|
||||
InvisibleSessionManager.setParameters(viewModel = viewModel, context = LocalContext.current)
|
||||
InvisibleSessionManager.setParameters(viewModel = viewModel, mediaPlayer = mediaPlayer)
|
||||
|
||||
val soundPlayer = SoundPlayer(LocalContext.current)
|
||||
val sessionActions = getSessionActions(viewModel, openAndPopUp)
|
||||
|
|
|
@ -15,10 +15,12 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import be.ugent.sel.studeez.common.composable.NewTaskSubjectButton
|
||||
import be.ugent.sel.studeez.common.composable.PrimaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.StealthButton
|
||||
import be.ugent.sel.studeez.common.composable.drawer.DrawerActions
|
||||
import be.ugent.sel.studeez.common.composable.navbar.NavigationBarActions
|
||||
import be.ugent.sel.studeez.common.composable.tasks.SubjectEntry
|
||||
import be.ugent.sel.studeez.data.local.models.task.Subject
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
@ -35,11 +37,11 @@ fun SubjectRoute(
|
|||
drawerActions = drawerActions,
|
||||
navigationBarActions = navigationBarActions,
|
||||
onAddSubject = { viewModel.onAddSubject(open) },
|
||||
onViewSubject = { viewModel.onViewSubject(it, open) },
|
||||
onViewSubject = { viewModel.onSelectSubject(it) { open(StudeezDestinations.TASKS_SCREEN) } },
|
||||
getTaskCount = viewModel::getTaskCount,
|
||||
getCompletedTaskCount = viewModel::getCompletedTaskCount,
|
||||
getStudyTime = viewModel::getStudyTime,
|
||||
uiState,
|
||||
uiState = uiState,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -76,14 +78,22 @@ fun SubjectScreen(
|
|||
) {
|
||||
NewTaskSubjectButton(onClick = onAddSubject, AppText.new_subject)
|
||||
LazyColumn {
|
||||
items(uiState.subjects) {
|
||||
items(uiState.subjects) { subject ->
|
||||
SubjectEntry(
|
||||
subject = it,
|
||||
onViewSubject = { onViewSubject(it) },
|
||||
getTaskCount = { getTaskCount(it) },
|
||||
getCompletedTaskCount = { getCompletedTaskCount(it) },
|
||||
getStudyTime = { getStudyTime(it) },
|
||||
)
|
||||
subject = subject,
|
||||
getTaskCount = { getTaskCount(subject) },
|
||||
getCompletedTaskCount = { getCompletedTaskCount(subject) },
|
||||
getStudyTime = { getStudyTime(subject) },
|
||||
) {
|
||||
StealthButton(
|
||||
text = AppText.view_tasks,
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp, end = 5.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
onViewSubject(subject)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,8 +42,8 @@ class SubjectViewModel @Inject constructor(
|
|||
return subjectDAO.getStudyTime(subject)
|
||||
}
|
||||
|
||||
fun onViewSubject(subject: Subject, open: (String) -> Unit) {
|
||||
fun onSelectSubject(subject: Subject, open: () -> Unit) {
|
||||
selectedSubject.set(subject)
|
||||
open(StudeezDestinations.TASKS_SCREEN)
|
||||
open()
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ import be.ugent.sel.studeez.common.composable.BasicButton
|
|||
import be.ugent.sel.studeez.common.composable.DeleteButton
|
||||
import be.ugent.sel.studeez.common.composable.FormComposable
|
||||
import be.ugent.sel.studeez.common.composable.LabelledInputField
|
||||
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.ext.basicButton
|
||||
import be.ugent.sel.studeez.common.ext.fieldModifier
|
||||
import be.ugent.sel.studeez.common.ext.generateRandomArgb
|
||||
|
|
|
@ -2,8 +2,6 @@ package be.ugent.sel.studeez.screens.subjects.form
|
|||
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import be.ugent.sel.studeez.common.ext.generateRandomArgb
|
||||
import be.ugent.sel.studeez.data.SelectedSubject
|
||||
import be.ugent.sel.studeez.data.local.models.task.Subject
|
||||
import be.ugent.sel.studeez.domain.LogService
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
package be.ugent.sel.studeez.screens.subjects.select
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import be.ugent.sel.studeez.R
|
||||
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.StealthButton
|
||||
import be.ugent.sel.studeez.common.composable.tasks.SubjectEntry
|
||||
import be.ugent.sel.studeez.data.local.models.task.Subject
|
||||
import be.ugent.sel.studeez.navigation.StudeezDestinations
|
||||
import be.ugent.sel.studeez.screens.subjects.SubjectUiState
|
||||
import be.ugent.sel.studeez.screens.subjects.SubjectViewModel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
@Composable
|
||||
fun SubjectSelectionRoute(
|
||||
open: (String) -> Unit,
|
||||
goBack: () -> Unit,
|
||||
viewModel: SubjectViewModel,
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
SubjectSelectionScreen(
|
||||
onViewSubject = { viewModel.onSelectSubject(it) { open(StudeezDestinations.ADD_TASK_FORM) } },
|
||||
getTaskCount = viewModel::getTaskCount,
|
||||
getCompletedTaskCount = viewModel::getCompletedTaskCount,
|
||||
getStudyTime = viewModel::getStudyTime,
|
||||
goBack = goBack,
|
||||
uiState = uiState,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SubjectSelectionScreen(
|
||||
goBack: () -> Unit,
|
||||
onViewSubject: (Subject) -> Unit,
|
||||
getTaskCount: (Subject) -> Flow<Int>,
|
||||
getCompletedTaskCount: (Subject) -> Flow<Int>,
|
||||
getStudyTime: (Subject) -> Flow<Int>,
|
||||
uiState: SubjectUiState,
|
||||
) {
|
||||
SecondaryScreenTemplate(
|
||||
title = stringResource(R.string.select_subject_title),
|
||||
barAction = {},
|
||||
popUp = goBack,
|
||||
) {
|
||||
when (uiState) {
|
||||
SubjectUiState.Loading -> Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
CircularProgressIndicator(color = MaterialTheme.colors.onBackground)
|
||||
}
|
||||
is SubjectUiState.Succes -> {
|
||||
Column(
|
||||
modifier = Modifier.padding(top = 5.dp)
|
||||
) {
|
||||
LazyColumn {
|
||||
items(uiState.subjects) { subject ->
|
||||
SubjectEntry(
|
||||
subject = subject,
|
||||
getTaskCount = { getTaskCount(subject) },
|
||||
getCompletedTaskCount = { getCompletedTaskCount(subject) },
|
||||
getStudyTime = { getStudyTime(subject) },
|
||||
) {
|
||||
StealthButton(
|
||||
text = R.string.select_subject,
|
||||
modifier = Modifier
|
||||
.padding(start = 4.dp, end = 4.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
onViewSubject(subject)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun SubjectScreenPreview() {
|
||||
SubjectSelectionScreen(
|
||||
goBack = {},
|
||||
onViewSubject = {},
|
||||
getTaskCount = { flowOf() },
|
||||
getCompletedTaskCount = { flowOf() },
|
||||
getStudyTime = { flowOf() },
|
||||
uiState = SubjectUiState.Succes(
|
||||
listOf(
|
||||
Subject(
|
||||
name = "Test Subject",
|
||||
argb_color = 0xFFFFD200,
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun SubjectScreenLoadingPreview() {
|
||||
SubjectSelectionScreen(
|
||||
goBack = {},
|
||||
onViewSubject = {},
|
||||
getTaskCount = { flowOf() },
|
||||
getCompletedTaskCount = { flowOf() },
|
||||
getStudyTime = { flowOf() },
|
||||
uiState = SubjectUiState.Loading,
|
||||
)
|
||||
}
|
|
@ -4,7 +4,6 @@ import androidx.annotation.StringRes
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import be.ugent.sel.studeez.common.composable.DeleteButton
|
||||
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
|
||||
import be.ugent.sel.studeez.common.composable.FormComposable
|
||||
import be.ugent.sel.studeez.data.local.models.timer_info.TimerInfo
|
||||
import be.ugent.sel.studeez.R.string as AppText
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import be.ugent.sel.studeez.common.composable.SecondaryScreenTemplate
|
||||
|
@ -46,4 +47,13 @@ fun TimerTypeSelectScreen(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun TimerTypeSelectScreenPreview() {
|
||||
TimerTypeSelectScreen(
|
||||
open = {},
|
||||
popUp = {}
|
||||
)
|
||||
}
|
|
@ -43,6 +43,7 @@
|
|||
<string name="tasks">Tasks</string>
|
||||
<string name="task">Task</string>
|
||||
<string name="my_subjects">My Subjects</string>
|
||||
<string name="select_subject_title">Select Subject</string>
|
||||
<string name="new_subject">New Subject</string>
|
||||
<string name="new_task">New Task</string>
|
||||
<string name="edit_subject">Edit Subject</string>
|
||||
|
@ -50,6 +51,7 @@
|
|||
<string name="delete_subject">Delete Subject</string>
|
||||
<string name="delete_task">Delete Task</string>
|
||||
<string name="view_tasks">View</string>
|
||||
<string name="select_subject">Select</string>
|
||||
<string name="regenerate_color">Regenerate Color</string>
|
||||
|
||||
<!-- Sessions -->
|
||||
|
@ -135,6 +137,9 @@
|
|||
<string name="send_friend_request">Send friend request</string>
|
||||
<string name="remove_friend">Remove as friend</string>
|
||||
<string name="show_profile">Show profile</string>
|
||||
<string name="click_search_friends">Click to search friends</string>
|
||||
<string name="searching_friends">Searching friends</string>
|
||||
<string name="already_friend">You are already befriended with that person.</string>
|
||||
|
||||
<!-- ========== Create & edit screens ========== -->
|
||||
|
||||
|
|
|
@ -7,13 +7,14 @@ import org.junit.Test
|
|||
class FunctionalPomodoroTimerUnitTest : FunctionalTimerUnitTest() {
|
||||
private val breakTime = 10
|
||||
private val breaks = 2
|
||||
private val repeats = 3 // = breaks + 1
|
||||
override val hours = 0
|
||||
override val minutes = 0
|
||||
override val seconds = 10
|
||||
private lateinit var pomodoroTimer: FunctionalPomodoroTimer
|
||||
|
||||
override fun setTimer() {
|
||||
pomodoroTimer = FunctionalPomodoroTimer(time, breakTime, breaks)
|
||||
pomodoroTimer = FunctionalPomodoroTimer(time, breakTime, repeats)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package be.ugent.sel.studeez.timer_functional
|
||||
|
||||
import android.media.MediaPlayer
|
||||
import be.ugent.sel.studeez.data.SelectedSessionReport
|
||||
import be.ugent.sel.studeez.data.SelectedTask
|
||||
import be.ugent.sel.studeez.data.SelectedTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalCustomTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalEndlessTimer
|
||||
import be.ugent.sel.studeez.data.local.models.timer_functional.FunctionalPomodoroTimer
|
||||
import be.ugent.sel.studeez.domain.LogService
|
||||
import be.ugent.sel.studeez.domain.implementation.LogServiceImpl
|
||||
import be.ugent.sel.studeez.screens.session.InvisibleSessionManager
|
||||
import be.ugent.sel.studeez.screens.session.SessionViewModel
|
||||
|
@ -22,13 +21,13 @@ import org.mockito.kotlin.mock
|
|||
class InvisibleSessionManagerTest {
|
||||
private var selectedTimer: SelectedTimer = SelectedTimer()
|
||||
private lateinit var viewModel: SessionViewModel
|
||||
private var mediaPlayer: MediaPlayer = mock()
|
||||
|
||||
|
||||
@Test
|
||||
fun InvisibleEndlessTimerTest() = runTest {
|
||||
selectedTimer.set(FunctionalEndlessTimer())
|
||||
viewModel = SessionViewModel(selectedTimer, SelectedSessionReport(), mock(), LogServiceImpl())
|
||||
InvisibleSessionManager.setParameters(viewModel, mediaPlayer)
|
||||
viewModel = SessionViewModel(selectedTimer, SelectedSessionReport(), SelectedTask(), LogServiceImpl())
|
||||
InvisibleSessionManager.setParameters(viewModel, mock())
|
||||
|
||||
val test = launch {
|
||||
InvisibleSessionManager.updateTimer()
|
||||
|
@ -47,10 +46,10 @@ class InvisibleSessionManagerTest {
|
|||
fun InvisiblePomodoroTimerTest() = runTest {
|
||||
val studyTime = 10
|
||||
val breakTime = 5
|
||||
val repeats = 1
|
||||
val repeats = 2
|
||||
selectedTimer.set(FunctionalPomodoroTimer(studyTime, breakTime, repeats))
|
||||
viewModel = SessionViewModel(selectedTimer, SelectedSessionReport(), mock(), LogServiceImpl())
|
||||
InvisibleSessionManager.setParameters(viewModel, mediaPlayer)
|
||||
viewModel = SessionViewModel(selectedTimer, SelectedSessionReport(), SelectedTask(), LogServiceImpl())
|
||||
InvisibleSessionManager.setParameters(viewModel, mock())
|
||||
|
||||
val test = launch {
|
||||
InvisibleSessionManager.updateTimer()
|
||||
|
@ -82,8 +81,8 @@ class InvisibleSessionManagerTest {
|
|||
@Test
|
||||
fun InvisibleCustomTimerTest() = runTest {
|
||||
selectedTimer.set(FunctionalCustomTimer(5))
|
||||
viewModel = SessionViewModel(selectedTimer, SelectedSessionReport(), mock(), LogServiceImpl())
|
||||
InvisibleSessionManager.setParameters(viewModel, mediaPlayer)
|
||||
viewModel = SessionViewModel(selectedTimer, SelectedSessionReport(), SelectedTask(), LogServiceImpl())
|
||||
InvisibleSessionManager.setParameters(viewModel, mock())
|
||||
|
||||
val test = launch {
|
||||
InvisibleSessionManager.updateTimer()
|
||||
|
|
Reference in a new issue