diff --git a/app/build.gradle b/app/build.gradle index 2bf496cd4..21bdf3c35 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:$gradlePluginVersion" + classpath 'com.android.tools.build:gradle:7.4.2' classpath files('libs/gradle-witness.jar') classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion" @@ -335,14 +335,13 @@ dependencies { testImplementation 'org.robolectric:shadows-multidex:4.4' implementation 'com.github.bumptech.glide:compose:1.0.0-alpha.1' - implementation 'androidx.compose.ui:ui:1.4.3' - implementation 'androidx.compose.ui:ui-tooling:1.4.3' + implementation 'androidx.compose.ui:ui:1.5.1' + implementation 'androidx.compose.ui:ui-tooling:1.5.1' implementation "com.google.accompanist:accompanist-themeadapter-appcompat:0.31.5-beta" implementation "com.google.accompanist:accompanist-pager-indicators:0.31.5-beta" - implementation "androidx.compose.runtime:runtime-livedata:1.4.3" - implementation 'androidx.compose.foundation:foundation-layout:1.5.0-alpha02' - implementation 'androidx.compose.material:material:1.5.0-alpha02' + implementation 'androidx.compose.foundation:foundation-layout:1.5.1' + implementation 'androidx.compose.material:material:1.5.1' } static def getLastCommitTimestamp() { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1ab19508d..4e8a36d82 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -115,7 +115,7 @@ android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.Session.DayNight.FlatActionBar" /> diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt index 330534e23..1a7420005 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt @@ -41,7 +41,7 @@ class AlbumThumbnailView : RelativeLayout { private var slides: List = listOf() private var slideSize: Int = 0 - override fun dispatchDraw(canvas: Canvas?) { + override fun dispatchDraw(canvas: Canvas) { super.dispatchDraw(canvas) cornerMask.mask(canvas) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailProgressBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailProgressBar.kt index 3abfd235c..d5ef6434e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailProgressBar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/ThumbnailProgressBar.kt @@ -30,9 +30,7 @@ class ThumbnailProgressBar: View { private val objectRect = Rect() private val drawingRect = Rect() - override fun dispatchDraw(canvas: Canvas?) { - if (canvas == null) return - + override fun dispatchDraw(canvas: Canvas) { getDrawingRect(objectRect) drawingRect.set(objectRect) diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/DisplayNameActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/DisplayNameActivity.kt deleted file mode 100644 index c0699e3eb..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/DisplayNameActivity.kt +++ /dev/null @@ -1,57 +0,0 @@ -package org.thoughtcrime.securesms.onboarding - -import android.content.Intent -import android.os.Bundle -import android.view.KeyEvent -import android.view.inputmethod.EditorInfo -import android.view.inputmethod.InputMethodManager -import android.widget.TextView.OnEditorActionListener -import android.widget.Toast -import network.loki.messenger.R -import network.loki.messenger.databinding.ActivityDisplayNameBinding -import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol -import org.thoughtcrime.securesms.BaseActionBarActivity -import org.thoughtcrime.securesms.util.push -import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo -import org.session.libsession.utilities.TextSecurePreferences - -class DisplayNameActivity : BaseActionBarActivity() { - private lateinit var binding: ActivityDisplayNameBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setUpActionBarSessionLogo() - binding = ActivityDisplayNameBinding.inflate(layoutInflater) - setContentView(binding.root) - with(binding) { - displayNameEditText.imeOptions = displayNameEditText.imeOptions or 16777216 // Always use incognito keyboard - displayNameEditText.setOnEditorActionListener( - OnEditorActionListener { _, actionID, event -> - if (actionID == EditorInfo.IME_ACTION_SEARCH || - actionID == EditorInfo.IME_ACTION_DONE || - (event.action == KeyEvent.ACTION_DOWN && - event.keyCode == KeyEvent.KEYCODE_ENTER)) { - register() - return@OnEditorActionListener true - } - false - }) - registerButton.setOnClickListener { register() } - } - } - - private fun register() { - val displayName = binding.displayNameEditText.text.toString().trim() - if (displayName.isEmpty()) { - return Toast.makeText(this, R.string.activity_display_name_display_name_missing_error, Toast.LENGTH_SHORT).show() - } - if (displayName.toByteArray().size > ProfileManagerProtocol.Companion.NAME_PADDED_LENGTH) { - return Toast.makeText(this, R.string.activity_display_name_display_name_too_long_error, Toast.LENGTH_SHORT).show() - } - val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - inputMethodManager.hideSoftInputFromWindow(binding.displayNameEditText.windowToken, 0) - TextSecurePreferences.setProfileName(this, displayName) - val intent = Intent(this, PNModeActivity::class.java) - push(intent) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/LandingActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/LandingActivity.kt index 8ca2fd5e6..666c4c79d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/LandingActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/LandingActivity.kt @@ -6,6 +6,7 @@ import network.loki.messenger.databinding.ActivityLandingBinding import org.session.libsession.utilities.TextSecurePreferences import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.crypto.IdentityKeyUtil +import org.thoughtcrime.securesms.onboarding.name.DisplayNameActivity import org.thoughtcrime.securesms.service.KeyCachingService import org.thoughtcrime.securesms.util.push import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/LoadingActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/LoadingActivity.kt index b2b7d7c71..293069f49 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/LoadingActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/LoadingActivity.kt @@ -24,6 +24,7 @@ import kotlinx.coroutines.launch import org.session.libsession.utilities.TextSecurePreferences import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.dependencies.ConfigFactory +import org.thoughtcrime.securesms.onboarding.name.DisplayNameActivity import org.thoughtcrime.securesms.ui.AppTheme import org.thoughtcrime.securesms.ui.ProgressArc import org.thoughtcrime.securesms.util.push diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/name/DisplayNameActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/name/DisplayNameActivity.kt new file mode 100644 index 000000000..59a605e71 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/name/DisplayNameActivity.kt @@ -0,0 +1,139 @@ +package org.thoughtcrime.securesms.onboarding.name + +import android.content.Intent +import android.os.Bundle +import android.view.inputmethod.InputMethodManager +import androidx.activity.viewModels +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.ContentAlpha +import androidx.compose.material.LocalContentAlpha +import androidx.compose.material.LocalContentColor +import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.material.TextFieldDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.lifecycleScope +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import network.loki.messenger.R +import network.loki.messenger.databinding.ActivityDisplayNameBinding +import org.thoughtcrime.securesms.BaseActionBarActivity +import org.thoughtcrime.securesms.onboarding.PNModeActivity +import org.thoughtcrime.securesms.ui.AppTheme +import org.thoughtcrime.securesms.ui.OutlineButton +import org.thoughtcrime.securesms.ui.PreviewTheme +import org.thoughtcrime.securesms.ui.base +import org.thoughtcrime.securesms.ui.baseBold +import org.thoughtcrime.securesms.ui.colorDestructive +import org.thoughtcrime.securesms.util.push +import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo + +@AndroidEntryPoint +class DisplayNameActivity : BaseActionBarActivity() { + private val viewModel: DisplayNameViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setUpActionBarSessionLogo() + + ComposeView(this) + .apply { setContent { DisplayNameScreen(viewModel) } } + .let(::setContentView) + + lifecycleScope.launch { + viewModel.eventFlow.collect { +// val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager +// inputMethodManager.hideSoftInputFromWindow(content.displayNameEditText.windowToken, 0) + + Intent(this@DisplayNameActivity, PNModeActivity::class.java).also(::push) + } + } + } + + @Composable + private fun DisplayNameScreen(viewModel: DisplayNameViewModel) { + val state = viewModel.stateFlow.collectAsState() + + AppTheme { + DisplayName(state.value, viewModel::onChange, viewModel::onContinue) + } + } + + @Preview + @Composable + fun PreviewDisplayName() { + PreviewTheme(R.style.Classic_Dark) { + DisplayName(State()) + } + } + + @Composable + fun DisplayName(state: State, onChange: (String) -> Unit = {}, onContinue: () -> Unit = {}) { + Column( + verticalArrangement = Arrangement.spacedBy(20.dp), + modifier = Modifier + .padding(horizontal = 50.dp) + .padding(bottom = 12.dp) + ) { + Spacer(modifier = Modifier.weight(1f)) + Text(stringResource(state.title), style = MaterialTheme.typography.h4) + Text( + stringResource(state.description), + style = MaterialTheme.typography.base, + modifier = Modifier.padding(bottom = 12.dp)) + + OutlinedTextField( + value = state.displayName, + onValueChange = { onChange(it) }, + placeholder = { Text(stringResource(R.string.activity_display_name_edit_text_hint)) }, + colors = TextFieldDefaults.outlinedTextFieldColors( + textColor = state.error?.let { colorDestructive } ?: + LocalContentColor.current.copy(LocalContentAlpha.current), + focusedBorderColor = Color(0xff414141), + unfocusedBorderColor = Color(0xff414141), + cursorColor = LocalContentColor.current, + placeholderColor = state.error?.let { colorDestructive } + ?: MaterialTheme.colors.onSurface.copy(ContentAlpha.medium) + ), + singleLine = true, + keyboardActions = KeyboardActions( + onDone = { viewModel.onContinue() }, + onGo = { viewModel.onContinue() }, + onSearch = { viewModel.onContinue() }, + onSend = { viewModel.onContinue() }, + ), + isError = state.error != null, + shape = RoundedCornerShape(12.dp) + ) + + state.error?.let { + Text(stringResource(it), style = MaterialTheme.typography.baseBold, color = MaterialTheme.colors.error) + } + + Spacer(modifier = Modifier.weight(2f)) + + OutlineButton( + stringResource(R.string.continue_2), + modifier = Modifier + .align(Alignment.CenterHorizontally) + .width(262.dp) + ) { onContinue() } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/name/DisplayNameViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/name/DisplayNameViewModel.kt new file mode 100644 index 000000000..e76ce8dfd --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/name/DisplayNameViewModel.kt @@ -0,0 +1,63 @@ +package org.thoughtcrime.securesms.onboarding.name + +import androidx.annotation.StringRes +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import network.loki.messenger.R +import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol.Companion.NAME_PADDED_LENGTH +import org.session.libsession.utilities.TextSecurePreferences +import javax.inject.Inject + +@HiltViewModel +class DisplayNameViewModel @Inject constructor( + private val prefs: TextSecurePreferences +): ViewModel() { + + private val state = MutableStateFlow(State()) + val stateFlow = state.asStateFlow() + + private val event = Channel() + val eventFlow = event.receiveAsFlow() + + fun onContinue() { + state.update { it.copy(displayName = it.displayName.trim()) } + + val displayName = state.value.displayName + + when { + displayName.isEmpty() -> { state.update { it.copy(error = R.string.activity_display_name_display_name_missing_error) } } + displayName.length > NAME_PADDED_LENGTH -> { state.update { it.copy(error = R.string.activity_display_name_display_name_too_long_error) } } + else -> { + prefs.setProfileName(displayName) + viewModelScope.launch { event.send(Event.DONE) } + } + } + } + + fun onChange(value: String) { + state.update { + it.copy( + displayName = value, + error = value.takeIf { it.length > NAME_PADDED_LENGTH }?.let { R.string.activity_display_name_display_name_too_long_error } + ) + } + } +} + +data class State( + @StringRes val title: Int = R.string.activity_display_name_title_2, + @StringRes val description: Int = R.string.activity_display_name_explanation, + @StringRes val error: Int? = null, + val displayName: String = "" +) + +sealed interface Event { + object DONE: Event +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt index 26949241d..cd2e6317c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Components.kt @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.ui import androidx.annotation.DrawableRes +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Canvas import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Box @@ -17,11 +18,13 @@ import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.ButtonColors +import androidx.compose.material.ButtonDefaults import androidx.compose.material.Card import androidx.compose.material.Colors import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedButton import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.Composable @@ -34,7 +37,6 @@ import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.res.painterResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView @@ -45,6 +47,22 @@ import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.components.ProfilePictureView import kotlin.math.roundToInt +@Composable +fun OutlineButton(text: String, modifier: Modifier = Modifier, onClick: () -> Unit) { + OutlinedButton( + modifier = modifier.size(108.dp, 34.dp), + onClick = onClick, + border = BorderStroke(1.dp, LocalExtraColors.current.prominentButtonColor), + shape = RoundedCornerShape(50), // = 50% percent + colors = ButtonDefaults.outlinedButtonColors( + contentColor = LocalExtraColors.current.prominentButtonColor, + backgroundColor = MaterialTheme.colors.background + ) + ){ + Text(text = text) + } +} + @Composable fun ItemButton( text: String, diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt index 9a23f2919..51610cd46 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt @@ -30,6 +30,7 @@ val LocalExtraColors = staticCompositionLocalOf { error("No Custom data class ExtraColors( val settingsBackground: Color, + val prominentButtonColor: Color ) /** @@ -42,6 +43,7 @@ fun AppTheme( val extraColors = LocalContext.current.run { ExtraColors( settingsBackground = getColorFromTheme(R.attr.colorSettingsBackground), + prominentButtonColor = getColorFromTheme(R.attr.prominentButtonColor), ) } @@ -98,6 +100,7 @@ val sessionTypography = Typography( ) val Typography.base get() = defaultStyle(14.sp) +val Typography.baseBold get() = boldStyle(14.sp) val Typography.small get() = defaultStyle(12.sp) val Typography.h7 get() = boldStyle(18.sp) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 76460e0dd..b84fb8aef 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -728,7 +728,7 @@ Enter the recovery phrase that was given to you when you signed up to restore your account. Enter your recovery phrase Pick your display name - This will be your name when you use Session. It can be your real name, an alias, or anything else you like. + It can be your real name, an alias, or anything else you like — and you can change it any time. Enter a display name Please pick a display name Please pick a shorter display name diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 428d37c5e..fff09af31 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -58,6 +58,7 @@ ?colorAccent @drawable/ic_document_small_dark @drawable/ic_document_large_dark + @color/destructive diff --git a/build.gradle b/build.gradle index 2cb531a7c..737bde2ab 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { } dependencies { - classpath "com.android.tools.build:gradle:$gradlePluginVersion" + classpath 'com.android.tools.build:gradle:7.4.2' classpath files('libs/gradle-witness.jar') classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion" @@ -77,6 +77,6 @@ allprojects { project.ext { androidMinimumSdkVersion = 23 androidTargetSdkVersion = 33 - androidCompileSdkVersion = 33 + androidCompileSdkVersion = 34 } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 1d7bc62d4..dbd8b30b6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,6 @@ #Mon Jun 26 09:56:43 AEST 2023 android.enableJetifier=true -gradlePluginVersion=7.3.1 org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" org.gradle.unsafe.configuration-cache=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cd825d084..ab85dbb69 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Thu Dec 30 07:09:53 SAST 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME