ui: add asset image on create channel view; allow to choose image on create profile (#6891)

* ui: create channel picture

* more centered

* better symmetry

* less diff

* choose image on create profile

* fix padding

* fix padding, fit into screen

* fix button layout

* placeholders

* fix padding

* channel pictures

* adjust asset_dir in scripts

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: shum <github.shum@liber.li>
This commit is contained in:
spaced4ndy
2026-04-27 13:00:14 +00:00
committed by GitHub
parent 3d85480944
commit 08c69e3dfa
18 changed files with 247 additions and 95 deletions
+3
View File
@@ -302,6 +302,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
shell: docker exec -t builder sh -eu {0}
run: |
export ASSETS_DIR='../../assets'
scripts/desktop/make-deb-linux.sh
- name: Prepare Desktop
@@ -327,6 +328,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == '22.04' && matrix.should_run == true
shell: docker exec -t builder sh -eu {0}
run: |
export ASSETS_DIR='../../assets'
scripts/desktop/make-appimage-linux.sh
- name: Prepare AppImage
@@ -549,6 +551,7 @@ jobs:
APPLE_SIMPLEX_NOTARIZATION_APPLE_ID: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_APPLE_ID }}
APPLE_SIMPLEX_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_PASSWORD }}
run: |
export ASSETS_DIR='../../assets'
scripts/ci/build-desktop-mac.sh
path=$(echo $PWD/apps/multiplatform/release/main/dmg/SimpleX-*.dmg)
echo "package_path=$path" >> $GITHUB_OUTPUT
@@ -10,6 +10,7 @@ import SwiftUI
import SimpleXChat
struct AddChannelView: View {
@Environment(\.colorScheme) var colorScheme
@EnvironmentObject var m: ChatModel
@EnvironmentObject var theme: AppTheme
@StateObject private var channelRelaysModel = ChannelRelaysModel.shared
@@ -45,28 +46,39 @@ struct AddChannelView: View {
private func profileStepView() -> some View {
List {
Group {
ZStack(alignment: .center) {
ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: profile.image, iconName: "antenna.radiowaves.left.and.right.circle.fill", size: 128)
if profile.image != nil {
Button {
profile.image = nil
} label: {
Image(systemName: "multiply")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 12)
HStack(spacing: 0) {
Spacer(minLength: 0)
ZStack(alignment: .center) {
ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: profile.image, iconName: "antenna.radiowaves.left.and.right.circle.fill", size: 128)
if profile.image != nil {
Button {
profile.image = nil
} label: {
Image(systemName: "multiply")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 12)
}
}
}
editImageButton { showChooseSource = true }
.buttonStyle(BorderlessButtonStyle())
}
editImageButton { showChooseSource = true }
.buttonStyle(BorderlessButtonStyle())
.padding(.horizontal, 10) // Offsets transparent space built into 3D asset
#if SIMPLEX_ASSETS
Spacer(minLength: 0)
Image(colorScheme == .light ? "create-channel" : "create-channel-light")
.resizable()
.scaledToFit()
.frame(height: 140)
#endif
Spacer(minLength: 0)
}
.frame(maxWidth: .infinity, alignment: .center)
}
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 0))
.listRowInsets(EdgeInsets(top: 8, leading: 0, bottom: 0, trailing: 0))
Section {
channelNameTextField()
@@ -68,6 +68,7 @@ struct AddGroupView: View {
List {
Group {
HStack(spacing: 0) {
Spacer(minLength: 0)
ZStack(alignment: .center) {
ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: profile.image, iconName: "person.2.circle.fill", size: 128)
@@ -86,16 +87,16 @@ struct AddGroupView: View {
editImageButton { showChooseSource = true }
.buttonStyle(BorderlessButtonStyle()) // otherwise whole "list row" is clickable
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 10) // Offsets transparent space built into 3D asset
#if SIMPLEX_ASSETS
Spacer(minLength: 0)
Image(colorScheme == .light ? "create-group" : "create-group-light")
.resizable()
.scaledToFit()
.frame(height: 140)
.frame(maxWidth: .infinity)
#endif
Spacer(minLength: 0)
}
.frame(maxWidth: .infinity)
}
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
@@ -29,45 +29,78 @@ enum UserProfileAlert: Identifiable {
let MAX_BIO_LENGTH_BYTES = 160
struct CreateProfile: View {
@Environment(\.colorScheme) var colorScheme
@Environment(\.dismiss) var dismiss
@EnvironmentObject var theme: AppTheme
@State private var displayName: String = ""
@State private var profileBio: String = ""
@FocusState private var focusDisplayName
@State private var alert: UserProfileAlert?
@State private var showChooseSource = false
@State private var showImagePicker = false
@State private var showTakePhoto = false
@State private var chosenImage: UIImage? = nil
@State private var profileImage: String? = nil
var body: some View {
List {
Section {
TextField("Enter your name…", text: $displayName)
.focused($focusDisplayName)
TextField("Bio", text: $profileBio)
Button {
createProfile()
} label: {
Label("Create profile", systemImage: "checkmark")
}
.disabled(!canCreateProfile(displayName) || !bioFitsLimit())
} header: {
HStack {
Text("Your profile")
.foregroundColor(theme.colors.secondary)
let name = displayName.trimmingCharacters(in: .whitespaces)
let validName = mkValidName(name)
if name != validName {
Spacer()
validationErrorIndicator {
alert = .invalidNameError(validName: validName)
}
} else if !bioFitsLimit() {
Spacer()
validationErrorIndicator {
showAlert(NSLocalizedString("Bio too large", comment: "alert title"))
Group {
ZStack(alignment: .center) {
ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: profileImage, size: 128)
if profileImage != nil {
Button {
profileImage = nil
} label: {
Image(systemName: "multiply")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 12)
}
}
}
editImageButton { showChooseSource = true }
.buttonStyle(BorderlessButtonStyle())
}
.frame(height: 20)
// TODO: add 3D asset image next to profile image (fix asset first - trim transparent space)
// #if SIMPLEX_ASSETS
// Image(colorScheme == .light ? "your-profile" : "your-profile-light")
// .resizable()
// .scaledToFit()
// .frame(height: 140)
// #endif
}
.frame(maxWidth: .infinity)
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets(top: 8, leading: 0, bottom: 0, trailing: 0))
Section {
ZStack(alignment: .leading) {
let name = displayName.trimmingCharacters(in: .whitespaces)
if name != mkValidName(name) {
Button {
alert = .invalidNameError(validName: mkValidName(name))
} label: {
Image(systemName: "exclamationmark.circle").foregroundColor(.red)
}
} else {
Image(systemName: "pencil").foregroundColor(theme.colors.secondary)
}
TextField("Enter your name…", text: $displayName)
.padding(.leading, 36)
.focused($focusDisplayName)
}
ZStack(alignment: .leading) {
Image(systemName: "pencil").foregroundColor(theme.colors.secondary)
TextField("Bio", text: $profileBio)
.padding(.leading, 36)
}
Button(action: createProfile) {
settingsRow("checkmark", color: theme.colors.primary) { Text("Create profile") }
}
.disabled(!canCreateProfile(displayName) || !bioFitsLimit())
} footer: {
VStack(alignment: .leading, spacing: 8) {
Text("Your profile is stored on your device and only shared with your contacts.")
@@ -75,10 +108,42 @@ struct CreateProfile: View {
.foregroundColor(theme.colors.secondary)
.frame(maxWidth: .infinity, alignment: .leading)
}
.compactSectionSpacing()
}
.navigationTitle("Create your profile")
.modifier(ThemedBackground(grouped: true))
.alert(item: $alert) { a in userProfileAlert(a, $displayName) }
.confirmationDialog("Profile image", isPresented: $showChooseSource, titleVisibility: .visible) {
Button("Take picture") {
showTakePhoto = true
}
Button("Choose from library") {
showImagePicker = true
}
}
.fullScreenCover(isPresented: $showTakePhoto) {
ZStack {
Color.black.edgesIgnoringSafeArea(.all)
CameraImagePicker(image: $chosenImage)
}
}
.sheet(isPresented: $showImagePicker) {
LibraryImagePicker(image: $chosenImage) { _ in
await MainActor.run {
showImagePicker = false
}
}
}
.onChange(of: chosenImage) { image in
Task {
let resized: String? = if let image {
await resizeImageToStrSize(cropToSquare(image), maxDataSize: 12500)
} else {
nil
}
await MainActor.run { profileImage = resized }
}
}
.onAppear() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
focusDisplayName = true
@@ -86,14 +151,6 @@ struct CreateProfile: View {
}
}
private func validationErrorIndicator(_ onTap: @escaping () -> Void) -> some View {
Image(systemName: "exclamationmark.circle")
.foregroundColor(.red)
.onTapGesture {
onTap()
}
}
private func bioFitsLimit() -> Bool {
chatJsonLength(profileBio) <= MAX_BIO_LENGTH_BYTES
}
@@ -104,7 +161,8 @@ struct CreateProfile: View {
let profile = Profile(
displayName: displayName.trimmingCharacters(in: .whitespaces),
fullName: "",
shortDescr: shortDescr
shortDescr: shortDescr,
image: profileImage
)
let m = ChatModel.shared
do {
+8 -8
View File
@@ -182,8 +182,8 @@
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; };
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; };
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz-ghc9.6.3.a */; };
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz.a */; };
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu-ghc9.6.3.a */; };
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu.a */; };
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; };
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; };
@@ -559,8 +559,8 @@
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz-ghc9.6.3.a"; sourceTree = "<group>"; };
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz.a"; sourceTree = "<group>"; };
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu-ghc9.6.3.a"; sourceTree = "<group>"; };
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu.a"; sourceTree = "<group>"; };
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = "<group>"; };
@@ -729,8 +729,8 @@
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */,
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */,
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */,
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz-ghc9.6.3.a in Frameworks */,
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz.a in Frameworks */,
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu-ghc9.6.3.a in Frameworks */,
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu.a in Frameworks */,
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -816,8 +816,8 @@
64C829992D54AEEE006B9E89 /* libffi.a */,
64C829982D54AEED006B9E89 /* libgmp.a */,
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */,
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz-ghc9.6.3.a */,
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.16-45m1zumjYj2Eu6IsS525uz.a */,
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu-ghc9.6.3.a */,
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.5.0.17-3blIIOCVZmm6YZ1Ew74Hcu.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -42,11 +42,14 @@ import chat.simplex.common.views.newchat.darkStops
import chat.simplex.common.views.newchat.gradientPoints
import chat.simplex.common.views.newchat.lightStops
import chat.simplex.common.views.onboarding.*
import chat.simplex.common.views.usersettings.DeleteImageButton
import chat.simplex.common.views.usersettings.EditImageButton
import chat.simplex.common.views.usersettings.SettingsActionItem
import chat.simplex.res.MR
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import java.net.URI
const val MAX_BIO_LENGTH_BYTES = 160
@@ -60,18 +63,63 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
val scrollState = rememberScrollState()
val keyboardState by getKeyboardState()
var savedKeyboardState by remember { mutableStateOf(keyboardState) }
Box(
modifier = Modifier
.fillMaxSize()
.padding(top = 20.dp)
) {
val displayName = rememberSaveable { mutableStateOf("") }
val shortDescr = rememberSaveable { mutableStateOf("") }
val focusRequester = remember { FocusRequester() }
val bottomSheetModalState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
val displayName = rememberSaveable { mutableStateOf("") }
val shortDescr = rememberSaveable { mutableStateOf("") }
val chosenImage = rememberSaveable { mutableStateOf<URI?>(null) }
val profileImage = rememberSaveable { mutableStateOf<String?>(null) }
val focusRequester = remember { FocusRequester() }
ModalBottomSheetLayout(
scrimColor = Color.Black.copy(alpha = 0.12F),
modifier = Modifier.imePadding(),
sheetContent = {
GetImageBottomSheet(
chosenImage,
onImageChange = { bitmap -> profileImage.value = resizeImageToStrSize(cropToSquare(bitmap), maxDataSize = 12500) },
hideBottomSheet = {
scope.launch { bottomSheetModalState.hide() }
})
},
sheetState = bottomSheetModalState,
sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp)
) {
Box(
modifier = Modifier.fillMaxSize()
) {
ColumnWithScrollBar {
AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING_HALF)
Row(
Modifier
.fillMaxWidth()
.padding(vertical = DEFAULT_PADDING_HALF),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Box(
contentAlignment = Alignment.Center
) {
Box(contentAlignment = Alignment.TopEnd) {
Box(contentAlignment = Alignment.Center) {
ProfileImage(128.dp, image = profileImage.value)
EditImageButton { scope.launch { bottomSheetModalState.show() } }
}
if (profileImage.value != null) {
DeleteImageButton { profileImage.value = null }
}
}
}
// TODO: add 3D asset image next to profile image (fix asset first - trim transparent space)
// if (BuildConfigCommon.SIMPLEX_ASSETS) {
// Image(
// painterResource(if (isInDarkTheme()) MR.images.your_profile_light else MR.images.your_profile),
// contentDescription = null,
// contentScale = ContentScale.Fit,
// modifier = Modifier.height(140.dp)
// )
// }
}
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
AppBarTitle(stringResource(MR.strings.create_profile), withPadding = false, bottomPadding = DEFAULT_PADDING)
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Text(
stringResource(MR.strings.display_name),
@@ -114,9 +162,9 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
iconColor = MaterialTheme.colors.primary,
click = {
if (chatModel.localUserCreated.value == true) {
createProfileInProfiles(chatModel, displayName.value, shortDescr.value, close)
createProfileInProfiles(chatModel, displayName.value, shortDescr.value, profileImage.value, close)
} else {
createProfileInNoProfileSetup(displayName.value, close)
createProfileInNoProfileSetup(displayName.value, profileImage.value, close)
}
},
)
@@ -137,6 +185,7 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
}
}
}
}
}
@Composable
@@ -304,9 +353,9 @@ private fun CreateFirstProfileDesktop(chatModel: ChatModel, close: () -> Unit) {
}
}
fun createProfileInNoProfileSetup(displayName: String, close: () -> Unit) {
fun createProfileInNoProfileSetup(displayName: String, image: String? = null, close: () -> Unit) {
withBGApi {
val user = controller.apiCreateActiveUser(null, Profile(displayName.trim(), "", null, null)) ?: return@withBGApi
val user = controller.apiCreateActiveUser(null, Profile(displayName.trim(), "", null, image)) ?: return@withBGApi
if (!chatModel.connectedToRemote()) {
chatModel.localUserCreated.value = true
}
@@ -317,11 +366,11 @@ fun createProfileInNoProfileSetup(displayName: String, close: () -> Unit) {
}
}
fun createProfileInProfiles(chatModel: ChatModel, displayName: String, shortDescr: String, close: () -> Unit) {
fun createProfileInProfiles(chatModel: ChatModel, displayName: String, shortDescr: String, image: String? = null, close: () -> Unit) {
withBGApi {
val rhId = chatModel.remoteHostId()
val user = chatModel.controller.apiCreateActiveUser(
rhId, Profile(displayName.trim(), "", shortDescr.trim().ifEmpty { null }, null)
rhId, Profile(displayName.trim(), "", shortDescr.trim().ifEmpty { null }, image)
) ?: return@withBGApi
chatModel.currentUser.value = user
if (chatModel.users.isEmpty()) {
@@ -23,6 +23,8 @@ import chat.simplex.common.model.*
import chat.simplex.common.model.ChatController.getUserServers
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
import androidx.compose.ui.layout.ContentScale
import chat.simplex.common.BuildConfigCommon
import chat.simplex.common.views.*
import chat.simplex.common.views.chat.group.GroupLinkView
import chat.simplex.common.views.chatlist.openGroupChat
@@ -257,22 +259,37 @@ private fun ProfileStepView(
) {
ModalView(close = close) {
ColumnWithScrollBar {
AppBarTitle(generalGetString(MR.strings.create_channel_title))
Box(
AppBarTitle(generalGetString(MR.strings.create_channel_title), bottomPadding = DEFAULT_PADDING_HALF)
Row(
Modifier
.fillMaxWidth()
.padding(bottom = 24.dp),
contentAlignment = Alignment.Center
.padding(vertical = DEFAULT_PADDING_HALF),
horizontalArrangement = if (BuildConfigCommon.SIMPLEX_ASSETS) Arrangement.SpaceEvenly else Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Box(contentAlignment = Alignment.TopEnd) {
Box(contentAlignment = Alignment.Center) {
ProfileImage(108.dp, image = profileImage.value, icon = MR.images.ic_bigtop_updates_circle_filled)
EditImageButton { scope.launch { bottomSheetModalState.show() } }
}
if (profileImage.value != null) {
DeleteImageButton { profileImage.value = null }
// Padding offsets transparent space built into 3D asset
Box(
modifier = if (BuildConfigCommon.SIMPLEX_ASSETS) Modifier.padding(horizontal = 3.dp) else Modifier,
contentAlignment = Alignment.Center
) {
Box(contentAlignment = Alignment.TopEnd) {
Box(contentAlignment = Alignment.Center) {
ProfileImage(128.dp, image = profileImage.value, icon = MR.images.ic_bigtop_updates_circle_filled)
EditImageButton { scope.launch { bottomSheetModalState.show() } }
}
if (profileImage.value != null) {
DeleteImageButton { profileImage.value = null }
}
}
}
if (BuildConfigCommon.SIMPLEX_ASSETS) {
Image(
painterResource(if (isInDarkTheme()) MR.images.create_channel_light else MR.images.create_channel),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier.height(140.dp)
)
}
}
Row(
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING_HALF).fillMaxWidth(),
@@ -109,7 +109,11 @@ fun AddGroupLayout(
horizontalArrangement = if (BuildConfigCommon.SIMPLEX_ASSETS) Arrangement.SpaceEvenly else Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Box(contentAlignment = Alignment.Center) {
// Padding offsets transparent space built into 3D asset
Box(
modifier = if (BuildConfigCommon.SIMPLEX_ASSETS) Modifier.padding(horizontal = 3.dp) else Modifier,
contentAlignment = Alignment.Center
) {
Box(contentAlignment = Alignment.TopEnd) {
Box(contentAlignment = Alignment.Center) {
ProfileImage(128.dp, image = profileImage.value, icon = MR.images.ic_supervised_user_circle_filled)
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M0,0h24v24H0z" fill="#00000000"/>
</svg>

After

Width:  |  Height:  |  Size: 175 B

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M0,0h24v24H0z" fill="#00000000"/>
</svg>

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

+2 -2
View File
@@ -16,5 +16,5 @@ security unlock-keychain -p "" /tmp/simplex.keychain
security list-keychains -s `security list-keychains | xargs` /tmp/simplex.keychain
scripts/desktop/build-lib-mac.sh
cd apps/multiplatform
./gradlew -Psimplex.assets.dir=../../assets packageDmg
./gradlew -Psimplex.assets.dir=../../assets notarizeDmg
./gradlew -Psimplex.assets.dir="$ASSETS_DIR" packageDmg
./gradlew -Psimplex.assets.dir="$ASSETS_DIR" notarizeDmg
+1 -1
View File
@@ -18,7 +18,7 @@ libcrypto_path=$(ldd common/src/commonMain/cpp/desktop/libs/*/libHSdirect-sqlcip
trap "rm common/src/commonMain/cpp/desktop/libs/*/`basename $libcrypto_path` 2> /dev/null || true" EXIT
cp $libcrypto_path common/src/commonMain/cpp/desktop/libs/*
./gradlew -Psimplex.assets.dir=../../assets createDistributable
./gradlew -Psimplex.assets.dir="$ASSETS_DIR" createDistributable
rm common/src/commonMain/cpp/desktop/libs/*/`basename $libcrypto_path`
rm -rf $release_app_dir/AppDir 2>/dev/null
+1 -1
View File
@@ -4,7 +4,7 @@ ARCH="$(uname -m)"
scripts/desktop/build-lib-linux.sh
cd apps/multiplatform
./gradlew -Psimplex.assets.dir=../../assets packageDeb
./gradlew -Psimplex.assets.dir="$ASSETS_DIR" packageDeb
# Workaround for skiko library
#
+2 -2
View File
@@ -110,7 +110,7 @@ for os_pair in ${oses}; do
# Desktop: deb
docker exec \
-t "${container_name}" \
sh -c './scripts/desktop/make-deb-linux.sh'
sh -c "export ASSETS_DIR='../../assets'; ./scripts/desktop/make-deb-linux.sh"
# Copy deb
docker cp \
@@ -128,7 +128,7 @@ for os_pair in ${oses}; do
# Appimage
docker exec \
-t "${container_name}" \
sh -c './scripts/desktop/make-appimage-linux.sh && mv ./apps/multiplatform/release/main/*imple*.AppImage ./apps/multiplatform/release/main/simplex.appimage'
sh -c "export ASSETS_DIR='../../assets'; ./scripts/desktop/make-appimage-linux.sh && mv ./apps/multiplatform/release/main/*imple*.AppImage ./apps/multiplatform/release/main/simplex.appimage"
# Copy appimage
docker cp \