Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private val nameMap = mapOf(
RespectImage.WORKS_OFFLINE to R.drawable.works_offline,
RespectImage.DATA_REPORTING to R.drawable.data_reporting,
RespectImage.ASSIGNMENTS to R.drawable.assignments
)
)

@Composable
actual fun respectImagePainter(image: RespectImage): Painter {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.selectable
Expand All @@ -15,6 +16,7 @@ import androidx.compose.material.RadioButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.filled.Email
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.filled.PersonAdd
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Share
Expand Down Expand Up @@ -86,6 +88,9 @@ fun InvitePersonScreen(
onApprovalRequiredChanged = viewModel::onApprovalEnabledChanged,
onRoleChange = viewModel::onRoleChange,
onClickResetCode = viewModel::onClickResetCode,
showSlider = viewModel::showSlider,
hideSlider = viewModel::hideSlider,
setSliderPage = viewModel::setSliderPage,
onSetClassInviteMode = viewModel::onSetClassInviteMode,
)
}
Expand All @@ -102,6 +107,9 @@ fun InvitePersonScreen(
onApprovalRequiredChanged: (Boolean) -> Unit,
onRoleChange: (PersonRoleEnum) -> Unit,
onClickResetCode: () -> Unit,
showSlider: () -> Unit,
hideSlider: () -> Unit,
setSliderPage: (Int) -> Unit,
onSetClassInviteMode: (ClassInviteModeEnum) -> Unit = { },
) {
val invite = uiState.invite.dataOrNull()
Expand All @@ -112,6 +120,13 @@ fun InvitePersonScreen(
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
if (uiState.showSlider){
InviteSliderBottomSheet(
uiState = uiState,
onPageChange = { setSliderPage(it) },
onDismiss = hideSlider
)
}

if(uiState.showRoleSelection) {
val selectedRole = uiState.selectedRole ?: uiState.roleOptions.firstOrNull()
Expand Down Expand Up @@ -166,21 +181,36 @@ fun InvitePersonScreen(

invite?.also {
Row(
modifier = Modifier.align(Alignment.CenterHorizontally).defaultItemPadding()
.clickable(enabled = fieldsEnabled) {
onClickInviteCode()
},
modifier = Modifier
.align(Alignment.CenterHorizontally)
.defaultItemPadding(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(Res.string.invite_code_label) + ": ",
textAlign = TextAlign.Center,
)
Row(
modifier = Modifier
.clickable(enabled = fieldsEnabled) {
onClickInviteCode()
}
) {
Text(
text = stringResource(Res.string.invite_code_label) + ": ",
textAlign = TextAlign.Center,
)

Text(
text = it.code,
textAlign = TextAlign.Center,
modifier = Modifier.testTag("invite_code"),
)
}

//Separated out for easier automated testing.
Text(
text = it.code,
textAlign = TextAlign.Center,
modifier = Modifier.testTag("invite_code"),
Icon(
imageVector = Icons.Default.Info,
contentDescription = null,
modifier = Modifier
.padding(start = 8.dp)
.size(18.dp)
.clickable { showSlider() }
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package world.respect.app.view.person.inviteperson

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.DrawableResource
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import world.respect.shared.generated.resources.Res
import world.respect.shared.generated.resources.enter_invite_code
import world.respect.shared.generated.resources.invite_how_title
import world.respect.shared.generated.resources.invite_step_confirm_desc
import world.respect.shared.generated.resources.invite_step_enter_code_desc
import world.respect.shared.generated.resources.invite_step_enter_code_title
import world.respect.shared.generated.resources.invite_step_open_app_desc
import world.respect.shared.generated.resources.invite_step_open_app_title
import world.respect.shared.generated.resources.invite_step_review_title
import world.respect.shared.generated.resources.invite_step_search_school_desc
import world.respect.shared.generated.resources.invite_step_search_school_title
import world.respect.shared.generated.resources.invite_step_share_desc
import world.respect.shared.generated.resources.invite_step_share_title
import world.respect.shared.generated.resources.open_respect_app
import world.respect.shared.generated.resources.review_and_complete_setup
import world.respect.shared.generated.resources.search_school
import world.respect.shared.generated.resources.share_invite_code
import world.respect.shared.viewmodel.person.inviteperson.InvitePersonUiState

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun InviteSliderBottomSheet(
uiState: InvitePersonUiState,
onPageChange: (Int) -> Unit,
onDismiss: () -> Unit
) {
val sliderPages = listOf(
InviteSliderPageUi(
sliderImage = Res.drawable.share_invite_code,
title = stringResource(Res.string.invite_step_share_title),
description = stringResource(
Res.string.invite_step_share_desc,
uiState.inviteCode?:""
)
),
InviteSliderPageUi(
sliderImage = Res.drawable.open_respect_app,
title = stringResource(Res.string.invite_step_open_app_title),
description = stringResource(Res.string.invite_step_open_app_desc)
),
InviteSliderPageUi(
sliderImage = Res.drawable.search_school,
title = stringResource(Res.string.invite_step_search_school_title),
description = stringResource(
Res.string.invite_step_search_school_desc,
uiState.schoolName?:""
)
),
InviteSliderPageUi(
sliderImage = Res.drawable.review_and_complete_setup,
title = stringResource(Res.string.invite_step_review_title),
description = stringResource(Res.string.invite_step_confirm_desc)
),
InviteSliderPageUi(
sliderImage = Res.drawable.enter_invite_code,
title = stringResource(Res.string.invite_step_enter_code_title),
description = stringResource(
Res.string.invite_step_enter_code_desc
)
)
)
val pagerState = rememberPagerState(
initialPage = uiState.currentSliderPage
) { sliderPages.size }

LaunchedEffect(pagerState.currentPage) {
onPageChange(pagerState.currentPage)
}
val sheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = true
)
if (uiState.showSlider) {
ModalBottomSheet(onDismissRequest = onDismiss,
sheetState = sheetState
) {
Column(
modifier = Modifier
.fillMaxWidth()
.height(390.dp)
) {
HorizontalPager(
state = pagerState,
modifier = Modifier.weight(1f)
) { page ->
val item = sliderPages[page]
Column(
modifier = Modifier
.fillMaxSize()
.padding(12.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(Res.string.invite_how_title),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
fontWeight = FontWeight.Bold
)
Image(
painter = painterResource(item.sliderImage),
contentDescription = null,
modifier = Modifier.size(200.dp).padding(8.dp)
.align(Alignment.CenterHorizontally)
)

Spacer(modifier = Modifier.height(10.dp))

Text(
text = item.title,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Start,
modifier = Modifier.fillMaxWidth(),
)
Text(item.description)
}
}

Row(
modifier = Modifier
.fillMaxWidth()
.padding(12.dp),
horizontalArrangement = Arrangement.Center
) {
repeat(sliderPages.size) { index ->
val selected = uiState.currentSliderPage == index
Box(
modifier = Modifier
.padding(horizontal = 4.dp)
.size(if (selected) 10.dp else 6.dp)
.clip(CircleShape)
.background(
if (selected) Color.Black else Color.LightGray
)
)
}
}
}
}
}
}

data class InviteSliderPageUi(
val sliderImage: DrawableResource,
val title: String,
val description: String
)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,23 @@

<string name="regenerate_invite_code">Regenerate invite code</string>
<string name="copy_link">Copy link</string>
<string name="invite_how_title">How to use an invite code</string>

<string name="invite_step_share_title">Share the Invite Code</string>
<string name="invite_step_share_desc">Give the invite code (%1$s) to the person you want to join the class. They can enter this code in the Respect app.</string>

<string name="invite_step_open_app_title">Open the Respect App</string>
<string name="invite_step_open_app_desc">Download and open the Respect app on your device. Tap Get Started to begin the joining process.</string>

<string name="invite_step_search_school_title">Search for Your School</string>
<string name="invite_step_search_school_desc">Type School name (e.g. %1$s) in the search bar. Select %1$s from the results list.</string>

<string name="invite_step_enter_code_title">Enter the Invite Code</string>
<string name="invite_step_enter_code_desc">Tap on "I have an Invite Code". Enter the code shared by your teacher.</string>

<string name="invite_step_confirm_desc">Confirm the class details shown on the screen. Create your profile and wait for teacher approval to join.</string>
<string name="invite_step_review_title">Review and Complete Setup</string>

<string name="invite_settings">Invite settings</string>
<string name="invite_multiple_allowed">Invite multiple people</string>
<string name="approval_required">Approval required</string>
Expand Down
Loading