feat: wiring together storage and configs for groups in a test way, experimenting with best structure that makes sense for group creation

This commit is contained in:
0x330a 2023-09-08 12:42:53 +10:00
parent 026f0056b9
commit de885b4b4a
6 changed files with 49 additions and 25 deletions

View file

@ -21,6 +21,7 @@ import network.loki.messenger.libsession_util.util.UserPic
import org.session.libsession.avatars.AvatarHelper
import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.BlindedIdMapping
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.calls.CallMessageType
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.AttachmentUploadJob
@ -880,15 +881,23 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
DatabaseComponent.get(context).groupDatabase().create(groupId, title, members, avatar, relay, admins, formationTimestamp)
}
override fun createNewGroup(groupName: String, groupDescription: String, members: List<SessionId>): Long? {
override fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Long? {
val userGroups = configFactory.userGroups ?: return null
val ourSessionId = getUserPublicKey() ?: return null
val userKp = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return null
val group = userGroups.createGroup()
userGroups.set(group)
val groupInfo = configFactory.groupInfoConfig(group.groupSessionId) ?: return null
val groupMembers = configFactory.groupMemberConfig(group.groupSessionId) ?: return null
val groupKeys = configFactory.groupKeysConfig(group.groupSessionId) ?: return null
val groupInfo = configFactory.getOrConstructGroupInfoConfig(group.groupSessionId) ?: return null
val groupMembers = configFactory.getOrConstructGroupMemberConfig(group.groupSessionId) ?: return null
val groupKeys = GroupKeysConfig.newInstance(
userKp.secretKey.asBytes,
Hex.fromStringCondensed(group.groupSessionId.publicKey),
group.adminKey,
info = groupInfo,
members = groupMembers
)
with (groupInfo) {
setName(groupName)
@ -1070,7 +1079,7 @@ open class Storage(context: Context, helper: SQLCipherOpenHelper, private val co
}
override fun getMembers(groupPublicKey: String): List<LibSessionGroupMember> =
configFactory.groupMemberConfig(SessionId.from(groupPublicKey))?.all()?.toList() ?: emptyList()
configFactory.getOrConstructGroupMemberConfig(SessionId.from(groupPublicKey))?.all()?.toList() ?: emptyList()
override fun setServerCapabilities(server: String, capabilities: List<String>) {
return DatabaseComponent.get(context).lokiAPIDatabase().setServerCapabilities(server, capabilities)

View file

@ -176,7 +176,7 @@ class ConfigFactory(
it.adminKey to it.authData
}
override fun groupInfoConfig(groupSessionId: SessionId): GroupInfoConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, _) ->
override fun getOrConstructGroupInfoConfig(groupSessionId: SessionId): GroupInfoConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, _) ->
// get any potential initial dumps
val dump = configDatabase.retrieveConfigAndHashes(
SharedConfigMessage.Kind.CLOSED_GROUP_INFO.name,
@ -186,15 +186,15 @@ class ConfigFactory(
GroupInfoConfig.newInstance(Hex.fromStringCondensed(groupSessionId.publicKey), sk, dump)
}
override fun groupKeysConfig(groupSessionId: SessionId): GroupKeysConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, _) ->
override fun getGroupKeysConfig(groupSessionId: SessionId): GroupKeysConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, _) ->
// Get the user info or return early
val (userSk, _) = maybeGetUserInfo() ?: return@let null
// Get the group info or return early
val info = groupInfoConfig(groupSessionId) ?: return@let null
val info = getOrConstructGroupInfoConfig(groupSessionId) ?: return@let null
// Get the group members or return early
val members = groupMemberConfig(groupSessionId) ?: return@let null
val members = getOrConstructGroupMemberConfig(groupSessionId) ?: return@let null
// Get the dump or empty
val dump = configDatabase.retrieveConfigAndHashes(
@ -213,7 +213,7 @@ class ConfigFactory(
)
}
override fun groupMemberConfig(groupSessionId: SessionId): GroupMembersConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, auth) ->
override fun getOrConstructGroupMemberConfig(groupSessionId: SessionId): GroupMembersConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, auth) ->
// Get initial dump if we have one
val dump = configDatabase.retrieveConfigAndHashes(
SharedConfigMessage.Kind.CLOSED_GROUP_MEMBERS.name,

View file

@ -22,6 +22,7 @@ import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@ -64,12 +65,13 @@ class CreateGroupFragment : Fragment() {
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val isLoading = viewModel.viewState.
return ComposeView(requireContext()).apply {
setContent {
CreateGroupScreen(createGroupState = CreateGroupState("", "", emptySet()))
// this is kind of annoying to require an initial state in the fragment and the VM
val currentState = viewModel.viewState.observeAsState(initial = ViewState.DEFAULT)
// create group state might be useful in future for adding members and returning
// to the create group state with a copy or something
CreateGroupScreen(currentState.value, createGroupState = CreateGroupState("", "", emptySet()))
}
}
}
@ -82,11 +84,15 @@ class CreateGroupFragment : Fragment() {
}
@Composable
fun CreateGroupScreen(createGroupState: CreateGroupState, modifier: Modifier = Modifier) {
fun CreateGroupScreen(viewState: ViewState,
createGroupState: CreateGroupState,
modifier: Modifier = Modifier) {
CreateGroup(
viewState,
createGroupState,
onCreate = {
onCreate = { newGroup ->
// launch something to create here
viewModel.tryCreateGroup(newGroup)
},
onClose = {
delegate.onDialogClosePressed()
@ -101,7 +107,11 @@ class CreateGroupFragment : Fragment() {
val isLoading: Boolean,
@StringRes val error: Int?,
val createdThreadId: Long?
)
) {
companion object {
val DEFAULT = ViewState(false, null, null)
}
}
}
@ -113,6 +123,7 @@ data class CreateGroupState (
@Composable
fun CreateGroup(
viewState: CreateGroupFragment.ViewState,
createGroupState: CreateGroupState,
onCreate: (CreateGroupState) -> Unit,
onBack: () -> Unit,
@ -165,7 +176,7 @@ fun CreateGroup(
// Create button
OutlinedButton(
onClick = { onCreate(CreateGroupState(name, description, members)) },
enabled = name.isNotBlank(),
enabled = name.isNotBlank() && !viewState.isLoading,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(16.dp),

View file

@ -21,7 +21,7 @@ class CreateGroupViewModel @Inject constructor(
private val _recipients = MutableLiveData<List<Recipient>>()
val recipients: LiveData<List<Recipient>> = _recipients
private val _viewState = MutableLiveData(CreateGroupFragment.ViewState(false, null, null))
private val _viewState = MutableLiveData(CreateGroupFragment.ViewState.DEFAULT)
val viewState: LiveData<CreateGroupFragment.ViewState> = _viewState
init {
@ -43,8 +43,12 @@ class CreateGroupViewModel @Inject constructor(
fun tryCreateGroup(createGroupState: CreateGroupState) {
_viewState.postValue(CreateGroupFragment.ViewState(true, null, null))
val name = createGroupState.groupName
val description = createGroupState.groupDescription
val members = createGroupState.members
// do some validations
if (createGroupState.groupName.isEmpty()) {
if (name.isEmpty()) {
return _viewState.postValue(
CreateGroupFragment.ViewState(false, R.string.error, null)
)
@ -52,7 +56,7 @@ class CreateGroupViewModel @Inject constructor(
// TODO: add future validation for empty group ? we'll add ourselves anyway ig
// make a group
storage.createGroup()
storage.createNewGroup(name, description, members)
}
fun filter(query: String): List<Recipient> {

View file

@ -155,7 +155,7 @@ interface StorageProtocol {
fun setExpirationTimer(address: String, duration: Int)
// Closed Groups
fun createNewGroup(groupName: String, groupDescription: String, members: List<SessionId>): Long?
fun createNewGroup(groupName: String, groupDescription: String, members: Set<SessionId>): Long?
fun getMembers(groupPublicKey: String): List<network.loki.messenger.libsession_util.util.GroupMember>
// Groups

View file

@ -16,9 +16,9 @@ interface ConfigFactoryProtocol {
val convoVolatile: ConversationVolatileConfig?
val userGroups: UserGroupsConfig?
fun groupInfoConfig(groupSessionId: SessionId): GroupInfoConfig?
fun groupKeysConfig(groupSessionId: SessionId): GroupKeysConfig?
fun groupMemberConfig(groupSessionId: SessionId): GroupMembersConfig?
fun getOrConstructGroupInfoConfig(groupSessionId: SessionId): GroupInfoConfig?
fun getOrConstructGroupMemberConfig(groupSessionId: SessionId): GroupMembersConfig?
fun getGroupKeysConfig(groupSessionId: SessionId): GroupKeysConfig?
fun getUserConfigs(): List<ConfigBase>
fun persist(forConfigObject: ConfigBase, timestamp: Long)