Merge pull request #549 from vector-im/feature/bma/onboardingServer
Onboarding iteration
This commit is contained in:
commit
ef7ddb8d0f
168 changed files with 3294 additions and 1406 deletions
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.atomic.atoms
|
||||
|
||||
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.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.LocalColors
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
|
||||
/**
|
||||
* RoundedIconAtom is an atom which displays an icon inside a rounded container.
|
||||
*
|
||||
* @param modifier the modifier to apply to this layout
|
||||
* @param size the size of the icon
|
||||
* @param resourceId the resource id of the icon to display, exclusive with [imageVector]
|
||||
* @param imageVector the image vector of the icon to display, exclusive with [resourceId]
|
||||
* @param tint the tint to apply to the icon
|
||||
*/
|
||||
@Composable
|
||||
fun RoundedIconAtom(
|
||||
modifier: Modifier = Modifier,
|
||||
size: RoundedIconAtomSize = RoundedIconAtomSize.Large,
|
||||
resourceId: Int? = null,
|
||||
imageVector: ImageVector? = null,
|
||||
tint: Color = MaterialTheme.colorScheme.secondary
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(size.toContainerSize())
|
||||
.background(
|
||||
color = LocalColors.current.quinary,
|
||||
shape = RoundedCornerShape(size.toCornerSize())
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(size.toIconSize()),
|
||||
tint = tint,
|
||||
resourceId = resourceId,
|
||||
imageVector = imageVector,
|
||||
contentDescription = "",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun RoundedIconAtomSize.toContainerSize(): Dp {
|
||||
return when (this) {
|
||||
RoundedIconAtomSize.Medium -> 30.dp
|
||||
RoundedIconAtomSize.Large -> 70.dp
|
||||
}
|
||||
}
|
||||
|
||||
private fun RoundedIconAtomSize.toCornerSize(): Dp {
|
||||
return when (this) {
|
||||
RoundedIconAtomSize.Medium -> 8.dp
|
||||
RoundedIconAtomSize.Large -> 14.dp
|
||||
}
|
||||
}
|
||||
|
||||
private fun RoundedIconAtomSize.toIconSize(): Dp {
|
||||
return when (this) {
|
||||
RoundedIconAtomSize.Medium -> 16.dp
|
||||
RoundedIconAtomSize.Large -> 48.dp
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun RoundedIconAtomLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun RoundedIconAtomDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
RoundedIconAtom(
|
||||
size = RoundedIconAtomSize.Medium,
|
||||
imageVector = Icons.Filled.Home,
|
||||
)
|
||||
RoundedIconAtom(
|
||||
size = RoundedIconAtomSize.Large,
|
||||
imageVector = Icons.Filled.Home,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
enum class RoundedIconAtomSize {
|
||||
Medium,
|
||||
Large
|
||||
}
|
||||
|
|
@ -16,55 +16,55 @@
|
|||
|
||||
package io.element.android.libraries.designsystem.atomic.molecules
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.ElementTextStyles
|
||||
import io.element.android.libraries.designsystem.R
|
||||
import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtom
|
||||
import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.LocalColors
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
/**
|
||||
* IconTitleSubtitleMolecule is a molecule which displays an icon, a title and a subtitle.
|
||||
*
|
||||
* @param title the title to display
|
||||
* @param subTitle the subtitle to display
|
||||
* @param modifier the modifier to apply to this layout
|
||||
* @param iconResourceId the resource id of the icon to display, exclusive with [iconImageVector]
|
||||
* @param iconImageVector the image vector of the icon to display, exclusive with [iconResourceId]
|
||||
* @param iconTint the tint to apply to the icon
|
||||
*/
|
||||
@Composable
|
||||
fun IconTitleSubtitleMolecule(
|
||||
iconResourceId: Int,
|
||||
title: String,
|
||||
subTitle: String,
|
||||
modifier: Modifier = Modifier,
|
||||
iconResourceId: Int? = null,
|
||||
iconImageVector: ImageVector? = null,
|
||||
iconTint: Color = MaterialTheme.colorScheme.primary,
|
||||
) {
|
||||
Column(modifier) {
|
||||
Box(
|
||||
RoundedIconAtom(
|
||||
modifier = Modifier
|
||||
.size(width = 70.dp, height = 70.dp)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.background(
|
||||
color = LocalColors.current.quinary,
|
||||
shape = RoundedCornerShape(14.dp)
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(width = 48.dp, height = 48.dp),
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
resourceId = iconResourceId,
|
||||
contentDescription = "",
|
||||
)
|
||||
}
|
||||
.align(Alignment.CenterHorizontally),
|
||||
size = RoundedIconAtomSize.Large,
|
||||
resourceId = iconResourceId,
|
||||
imageVector = iconImageVector,
|
||||
tint = iconTint,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
text = title,
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ fun LabelledTextField(
|
|||
value: String,
|
||||
modifier: Modifier = Modifier,
|
||||
placeholder: String? = null,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
singleLine: Boolean = false,
|
||||
maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
|
||||
onValueChange: (String) -> Unit = {},
|
||||
) {
|
||||
Column(
|
||||
|
|
|
|||
|
|
@ -24,12 +24,14 @@ import androidx.compose.foundation.layout.padding
|
|||
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 io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@Composable
|
||||
fun AsyncFailure(
|
||||
|
|
@ -43,11 +45,11 @@ fun AsyncFailure(
|
|||
.padding(vertical = 32.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(text = throwable.message ?: "An error occurred")
|
||||
Text(text = throwable.message ?: stringResource(id = StringR.string.error_unknown))
|
||||
if (onRetry != null) {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Button(onClick = onRetry) {
|
||||
Text(text = "Retry")
|
||||
Text(text = stringResource(id = StringR.string.action_retry))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,5 +22,5 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.remember
|
||||
|
||||
@Composable
|
||||
public fun textFieldState(stateValue: String): MutableState<String> =
|
||||
fun textFieldState(stateValue: String): MutableState<String> =
|
||||
remember(stateValue) { mutableStateOf(stateValue) }
|
||||
|
|
|
|||
|
|
@ -69,14 +69,11 @@ fun PreferenceView(
|
|||
)
|
||||
},
|
||||
content = {
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(it)
|
||||
.consumeWindowInsets(it)
|
||||
.verticalScroll(
|
||||
state = scrollState,
|
||||
)
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
) {
|
||||
content()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,54 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
/**
|
||||
* Icon is a wrapper around [androidx.compose.material3.Icon] which allows to use
|
||||
* [ImageVector], [ImageBitmap] or [DrawableRes] as icon source.
|
||||
*
|
||||
* @param contentDescription the content description to be used for accessibility
|
||||
* @param modifier the modifier to apply to this layout
|
||||
* @param tint the tint to apply to the icon
|
||||
* @param imageVector the image vector of the icon to display, exclusive with [bitmap] and [resourceId]
|
||||
* @param bitmap the bitmap of the icon to display, exclusive with [imageVector] and [resourceId]
|
||||
* @param resourceId the resource id of the icon to display, exclusive with [imageVector] and [bitmap]
|
||||
*/
|
||||
@Composable
|
||||
fun Icon(
|
||||
contentDescription: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
tint: Color = LocalContentColor.current,
|
||||
imageVector: ImageVector? = null,
|
||||
bitmap: ImageBitmap? = null,
|
||||
@DrawableRes resourceId: Int? = null,
|
||||
) {
|
||||
when {
|
||||
imageVector != null -> {
|
||||
Icon(
|
||||
imageVector = imageVector,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
tint = tint
|
||||
)
|
||||
}
|
||||
bitmap != null -> {
|
||||
Icon(
|
||||
bitmap = bitmap,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
tint = tint
|
||||
)
|
||||
}
|
||||
resourceId != null -> {
|
||||
Icon(
|
||||
resourceId = resourceId,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
tint = tint
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Icon(
|
||||
imageVector: ImageVector,
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ fun OutlinedTextField(
|
|||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
singleLine: Boolean = false,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
shape: Shape = OutlinedTextFieldDefaults.shape,
|
||||
colors: TextFieldColors = OutlinedTextFieldDefaults.colors()
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ fun TextField(
|
|||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
singleLine: Boolean = false,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
shape: Shape = TextFieldDefaults.shape,
|
||||
colors: TextFieldColors = TextFieldDefaults.colors()
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
|||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
class StateContentFormatter @Inject constructor(
|
||||
private val sp: StringProvider,
|
||||
|
|
@ -49,7 +50,7 @@ class StateContentFormatter @Inject constructor(
|
|||
sp.getString(R.string.state_event_room_created, senderDisplayName)
|
||||
}
|
||||
}
|
||||
is OtherState.RoomEncryption -> sp.getString(io.element.android.libraries.ui.strings.R.string.common_encryption_enabled)
|
||||
is OtherState.RoomEncryption -> sp.getString(StringR.string.common_encryption_enabled)
|
||||
is OtherState.RoomName -> {
|
||||
val hasRoomName = content.name != null
|
||||
when {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ object TestTags {
|
|||
* Change server screen.
|
||||
*/
|
||||
val changeServerServer = TestTag("change_server-server")
|
||||
val changeServerContinue = TestTag("change_server-continue")
|
||||
|
||||
/**
|
||||
* Room list / Home screen.
|
||||
|
|
|
|||
|
|
@ -150,12 +150,6 @@
|
|||
<string name="screen_media_upload_preview_error_failed_processing">"Nahrání média se nezdařilo, zkuste to prosím znovu."</string>
|
||||
<string name="screen_media_upload_preview_error_failed_sending">"Nahrání média se nezdařilo, zkuste to prosím znovu."</string>
|
||||
<string name="screen_report_content_block_user_hint">"Zaškrtněte, pokud chcete skrýt všechny aktuální a budoucí zprávy od tohoto uživatele"</string>
|
||||
<string name="screen_server_confirmation_change_server">"Změnit poskytovatele účtu"</string>
|
||||
<string name="screen_server_confirmation_message_login_element_dot_io">"Soukromý server pro zaměstnance Elementu."</string>
|
||||
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix je otevřená síť pro bezpečnou a decentralizovanou komunikaci."</string>
|
||||
<string name="screen_server_confirmation_message_register">"Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily."</string>
|
||||
<string name="screen_server_confirmation_title_login">"Chystáte se přihlásit do služby %1$s"</string>
|
||||
<string name="screen_server_confirmation_title_register">"Chystáte se vytvořit účet na %1$s"</string>
|
||||
<string name="settings_rageshake">"Rageshake"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Práh detekce"</string>
|
||||
<string name="settings_title_general">"Obecné"</string>
|
||||
|
|
|
|||
|
|
@ -142,9 +142,6 @@
|
|||
<string name="screen_media_picker_error_failed_selection">"Medienauswahl fehlgeschlagen, bitte versuche es erneut."</string>
|
||||
<string name="screen_media_upload_preview_error_failed_sending">"Medien hochladen fehlgeschlagen. Bitte versuchen Sie es erneut."</string>
|
||||
<string name="screen_report_content_block_user_hint">"Prüfe, ob du alle aktuellen und zukünftigen Nachrichten dieses Benutzers ausblenden möchtest"</string>
|
||||
<string name="screen_server_confirmation_change_server">"Kontoanbieter wechseln"</string>
|
||||
<string name="screen_server_confirmation_message_login_element_dot_io">"Ein privater Server für Element-Mitarbeiter."</string>
|
||||
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix ist ein offenes Netzwerk für sichere, dezentrale Kommunikation"</string>
|
||||
<string name="settings_rageshake">"Rageshake"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Erkennungsschwelle"</string>
|
||||
<string name="settings_title_general">"Allgemein"</string>
|
||||
|
|
@ -156,4 +153,4 @@
|
|||
<string name="screen_analytics_settings_read_terms">"Sie können alle unsere Nutzerbedingungen %1$s lesen."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"hier"</string>
|
||||
<string name="screen_report_content_block_user">"Nutzer blockieren"</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -57,9 +57,11 @@
|
|||
<string name="action_view_source">"View Source"</string>
|
||||
<string name="action_yes">"Yes"</string>
|
||||
<string name="common_about">"About"</string>
|
||||
<string name="common_acceptable_use_policy">"Acceptable use policy"</string>
|
||||
<string name="common_analytics">"Analytics"</string>
|
||||
<string name="common_audio">"Audio"</string>
|
||||
<string name="common_bubbles">"Bubbles"</string>
|
||||
<string name="common_copyright">"Copyright"</string>
|
||||
<string name="common_creating_room">"Creating room…"</string>
|
||||
<string name="common_current_user_left_room">"Left room"</string>
|
||||
<string name="common_decryption_error">"Decryption error"</string>
|
||||
|
|
@ -81,11 +83,13 @@
|
|||
<string name="common_message_layout">"Message layout"</string>
|
||||
<string name="common_message_removed">"Message removed"</string>
|
||||
<string name="common_modern">"Modern"</string>
|
||||
<string name="common_mute">"Mute"</string>
|
||||
<string name="common_no_results">"No results"</string>
|
||||
<string name="common_offline">"Offline"</string>
|
||||
<string name="common_password">"Password"</string>
|
||||
<string name="common_people">"People"</string>
|
||||
<string name="common_permalink">"Permalink"</string>
|
||||
<string name="common_privacy_policy">"Privacy policy"</string>
|
||||
<string name="common_reactions">"Reactions"</string>
|
||||
<string name="common_replying_to">"Replying to %1$s"</string>
|
||||
<string name="common_report_a_bug">"Report a bug"</string>
|
||||
|
|
@ -104,11 +108,13 @@
|
|||
<string name="common_sticker">"Sticker"</string>
|
||||
<string name="common_success">"Success"</string>
|
||||
<string name="common_suggestions">"Suggestions"</string>
|
||||
<string name="common_third_party_notices">"Third-party notices"</string>
|
||||
<string name="common_topic">"Topic"</string>
|
||||
<string name="common_topic_placeholder">"What is this room about?"</string>
|
||||
<string name="common_unable_to_decrypt">"Unable to decrypt"</string>
|
||||
<string name="common_unable_to_invite_message">"We were unable to successfully send invites to one or more users."</string>
|
||||
<string name="common_unable_to_invite_title">"Unable to send invite(s)"</string>
|
||||
<string name="common_unmute">"Unmute"</string>
|
||||
<string name="common_unsupported_event">"Unsupported event"</string>
|
||||
<string name="common_username">"Username"</string>
|
||||
<string name="common_verification_cancelled">"Verification cancelled"</string>
|
||||
|
|
@ -164,12 +170,6 @@
|
|||
<string name="screen_media_upload_preview_error_failed_processing">"Failed processing media to upload, please try again."</string>
|
||||
<string name="screen_media_upload_preview_error_failed_sending">"Failed uploading media, please try again."</string>
|
||||
<string name="screen_report_content_block_user_hint">"Check if you want to hide all current and future messages from this user"</string>
|
||||
<string name="screen_server_confirmation_change_server">"Change account provider"</string>
|
||||
<string name="screen_server_confirmation_message_login_element_dot_io">"A private server for Element employees."</string>
|
||||
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix is an open network for secure, decentralised communication."</string>
|
||||
<string name="screen_server_confirmation_message_register">"This is where your conversations will live — just like you would use an email provider to keep your emails."</string>
|
||||
<string name="screen_server_confirmation_title_login">"You’re about to sign in to %1$s"</string>
|
||||
<string name="screen_server_confirmation_title_register">"You’re about to create an account on %1$s"</string>
|
||||
<string name="settings_rageshake">"Rageshake"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Detection threshold"</string>
|
||||
<string name="settings_title_general">"General"</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue