Browse Source

Introduce SessionComponent

feature/bma/flipper
ganfra 2 years ago
parent
commit
9aa0ce9438
  1. 20
      app/src/main/java/io/element/android/x/ElementXApplication.kt
  2. 18
      app/src/main/java/io/element/android/x/MainViewModel.kt
  3. 9
      app/src/main/java/io/element/android/x/Navigation.kt
  4. 2
      app/src/main/java/io/element/android/x/di/AppBindings.kt
  5. 27
      app/src/main/java/io/element/android/x/di/SessionComponent.kt
  6. 45
      app/src/main/java/io/element/android/x/di/SessionComponentsOwner.kt
  7. 8
      app/src/main/java/io/element/android/x/initializer/CoilInitializer.kt
  8. 20
      features/login/src/main/java/io/element/android/x/features/login/LoginScreen.kt
  9. 12
      features/login/src/main/java/io/element/android/x/features/login/LoginViewModel.kt
  10. 5
      features/login/src/main/java/io/element/android/x/features/login/LoginViewState.kt
  11. 19
      features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewModel.kt
  12. 7
      features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt
  13. 10
      features/messages/src/main/java/io/element/android/x/features/messages/textcomposer/MessageComposerViewModel.kt
  14. 7
      features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt
  15. 33
      libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt
  16. 6
      libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt
  17. 19
      libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixInstance.kt
  18. 13
      libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaFetcher.kt

20
app/src/main/java/io/element/android/x/ElementXApplication.kt

@ -3,29 +3,33 @@ package io.element.android.x @@ -3,29 +3,33 @@ package io.element.android.x
import android.app.Application
import androidx.startup.AppInitializer
import io.element.android.x.core.di.DaggerComponentOwner
import io.element.android.x.core.di.bindings
import io.element.android.x.di.AppBindings
import io.element.android.x.di.AppComponent
import io.element.android.x.di.DaggerAppComponent
import io.element.android.x.di.SessionComponentsOwner
import io.element.android.x.initializer.CoilInitializer
import io.element.android.x.initializer.MatrixInitializer
import io.element.android.x.initializer.MavericksInitializer
import io.element.android.x.matrix.MatrixInstance
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.plus
class ElementXApplication : Application(), DaggerComponentOwner {
override lateinit var daggerComponent: Any
private lateinit var appComponent: AppComponent
private var sessionComponentsOwner: SessionComponentsOwner? = null
private val applicationScope = MainScope() + CoroutineName("ElementX Scope")
override val daggerComponent: Any
get() = listOfNotNull(sessionComponentsOwner?.activeSessionComponent, appComponent)
override fun onCreate() {
super.onCreate()
daggerComponent = DaggerAppComponent.factory().create(applicationContext)
MatrixInstance.init(this, applicationScope)
appComponent = DaggerAppComponent.factory().create(applicationContext)
sessionComponentsOwner = bindings<AppBindings>().sessionComponentsOwner()
AppInitializer.getInstance(this).apply {
initializeComponent(MatrixInitializer::class.java)
initializeComponent(CoilInitializer::class.java)
initializeComponent(MavericksInitializer::class.java)
}
}
}

18
app/src/main/java/io/element/android/x/MainViewModel.kt

@ -8,8 +8,7 @@ import dagger.assisted.AssistedInject @@ -8,8 +8,7 @@ import dagger.assisted.AssistedInject
import io.element.android.x.anvilannotations.ContributesViewModel
import io.element.android.x.core.di.daggerMavericksViewModelFactory
import io.element.android.x.di.AppScope
import io.element.android.x.features.messages.MessagesViewModel
import io.element.android.x.features.messages.model.MessagesViewState
import io.element.android.x.di.SessionComponentsOwner
import io.element.android.x.matrix.Matrix
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
@ -19,10 +18,12 @@ data class MainState(val fake: Boolean = false) : MavericksState @@ -19,10 +18,12 @@ data class MainState(val fake: Boolean = false) : MavericksState
@ContributesViewModel(AppScope::class)
class MainViewModel @AssistedInject constructor(
private val matrix: Matrix,
private val sessionComponentsOwner: SessionComponentsOwner,
@Assisted initialState: MainState
) : MavericksViewModel<MainState>(initialState) {
companion object : MavericksViewModelFactory<MainViewModel, MainState> by daggerMavericksViewModelFactory()
companion object :
MavericksViewModelFactory<MainViewModel, MainState> by daggerMavericksViewModelFactory()
suspend fun isLoggedIn(): Boolean {
return matrix.isLoggedIn().first()
@ -31,19 +32,22 @@ class MainViewModel @AssistedInject constructor( @@ -31,19 +32,22 @@ class MainViewModel @AssistedInject constructor(
fun startSyncIfLogged() {
viewModelScope.launch {
if (!isLoggedIn()) return@launch
matrix.activeClient().startSync()
}
}
fun stopSyncIfLogged() {
viewModelScope.launch {
if (!isLoggedIn()) return@launch
matrix.activeClient().stopSync()
}
}
suspend fun restoreSession() {
matrix.restoreSession()
matrix.activeClient().startSync()
val matrixClient = matrix.restoreSession()
if (matrixClient == null) {
throw IllegalStateException("Couldn't restore session...")
} else {
sessionComponentsOwner.create(matrixClient)
matrixClient.startSync()
}
}
}

9
app/src/main/java/io/element/android/x/Navigation.kt

@ -1,11 +1,14 @@ @@ -1,11 +1,14 @@
package io.element.android.x
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootNavGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
import io.element.android.x.core.di.bindings
import io.element.android.x.destinations.*
import io.element.android.x.di.AppBindings
import io.element.android.x.features.login.LoginScreen
import io.element.android.x.features.login.changeserver.ChangeServerScreen
import io.element.android.x.features.messages.MessagesScreen
@ -29,11 +32,13 @@ fun OnBoardingScreenNavigation(navigator: DestinationsNavigator) { @@ -29,11 +32,13 @@ fun OnBoardingScreenNavigation(navigator: DestinationsNavigator) {
@Destination
@Composable
fun LoginScreenNavigation(navigator: DestinationsNavigator) {
val sessionComponentsOwner = LocalContext.current.bindings<AppBindings>().sessionComponentsOwner()
LoginScreen(
onChangeServer = {
navigator.navigate(ChangeServerScreenNavigationDestination)
},
onLoginWithSuccess = {
sessionComponentsOwner.create(it)
navigator.navigate(RoomListScreenNavigationDestination) {
popUpTo(OnBoardingScreenNavigationDestination) {
inclusive = true
@ -58,11 +63,13 @@ fun ChangeServerScreenNavigation(navigator: DestinationsNavigator) { @@ -58,11 +63,13 @@ fun ChangeServerScreenNavigation(navigator: DestinationsNavigator) {
@Destination
@Composable
fun RoomListScreenNavigation(navigator: DestinationsNavigator) {
val sessionComponentsOwner = LocalContext.current.bindings<AppBindings>().sessionComponentsOwner()
RoomListScreen(
onRoomClicked = { roomId: RoomId ->
navigator.navigate(MessagesScreenNavigationDestination(roomId = roomId.value))
},
onSuccessLogout = {
sessionComponentsOwner.releaseActiveSession()
navigator.navigate(OnBoardingScreenNavigationDestination) {
popUpTo(RoomListScreenNavigationDestination) {
inclusive = true
@ -75,7 +82,7 @@ fun RoomListScreenNavigation(navigator: DestinationsNavigator) { @@ -75,7 +82,7 @@ fun RoomListScreenNavigation(navigator: DestinationsNavigator) {
@Destination
@Composable
fun MessagesScreenNavigation(roomId: String, navigator: DestinationsNavigator) {
MessagesScreen(roomId, navigator::navigateUp)
MessagesScreen(roomId = roomId, onBackPressed = navigator::navigateUp)
}

2
app/src/main/java/io/element/android/x/di/AppBindings.kt

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
package io.element.android.x.di
import com.squareup.anvil.annotations.ContributesTo
import io.element.android.x.di.AppScope
import io.element.android.x.matrix.Matrix
import kotlinx.coroutines.CoroutineScope
@ -9,4 +8,5 @@ import kotlinx.coroutines.CoroutineScope @@ -9,4 +8,5 @@ import kotlinx.coroutines.CoroutineScope
interface AppBindings {
fun coroutineScope(): CoroutineScope
fun matrix(): Matrix
fun sessionComponentsOwner(): SessionComponentsOwner
}

27
app/src/main/java/io/element/android/x/di/SessionComponent.kt

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
package io.element.android.x.di
import com.squareup.anvil.annotations.ContributesTo
import com.squareup.anvil.annotations.MergeSubcomponent
import dagger.BindsInstance
import dagger.Subcomponent
import io.element.android.x.core.di.DaggerMavericksBindings
import io.element.android.x.matrix.MatrixClient
@SingleIn(SessionScope::class)
@MergeSubcomponent(SessionScope::class)
interface SessionComponent: DaggerMavericksBindings {
fun matrixClient(): MatrixClient
@Subcomponent.Builder
interface Builder {
@BindsInstance
fun client(matrixClient: MatrixClient): Builder
fun build(): SessionComponent
}
@ContributesTo(AppScope::class)
interface ParentBindings {
fun sessionComponentBuilder(): Builder
}
}

45
app/src/main/java/io/element/android/x/di/SessionComponentsOwner.kt

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
package io.element.android.x.di
import android.content.Context
import io.element.android.x.core.di.bindings
import io.element.android.x.matrix.MatrixClient
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
@SingleIn(AppScope::class)
class SessionComponentsOwner @Inject constructor(@ApplicationContext private val context: Context) {
private val sessionComponents = ConcurrentHashMap<String, SessionComponent>()
var activeSessionComponent: SessionComponent? = null
private set
fun setActive(sessionId: String) {
val sessionComponent = sessionComponents[sessionId]
if (activeSessionComponent != sessionComponent) {
activeSessionComponent = sessionComponent
}
}
fun create(matrixClient: MatrixClient) {
val sessionId = matrixClient.sessionId
val sessionComponent =
context.bindings<SessionComponent.ParentBindings>().sessionComponentBuilder()
.client(matrixClient).build()
sessionComponents[sessionId] = sessionComponent
setActive(sessionId)
}
fun releaseActiveSession() {
activeSessionComponent?.also {
release(it.matrixClient().sessionId)
}
}
fun release(sessionId: String) {
val sessionComponent = sessionComponents.remove(sessionId)
if (activeSessionComponent == sessionComponent) {
activeSessionComponent = null
}
}
}

8
app/src/main/java/io/element/android/x/initializer/CoilInitializer.kt

@ -25,7 +25,13 @@ private class ElementImageLoaderFactory( @@ -25,7 +25,13 @@ private class ElementImageLoaderFactory(
return ImageLoader
.Builder(context)
.components {
context.bindings<AppBindings>().matrix().registerCoilComponents(this)
val appBindings = context.bindings<AppBindings>()
val matrix = appBindings.matrix()
val matrixClientProvider = {
appBindings
.sessionComponentsOwner().activeSessionComponent?.matrixClient()
}
matrix.registerCoilComponents(this, matrixClientProvider)
}
.build()
}

20
features/login/src/main/java/io/element/android/x/features/login/LoginScreen.kt

@ -30,13 +30,14 @@ import com.airbnb.mvrx.compose.collectAsState @@ -30,13 +30,14 @@ import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel
import io.element.android.x.designsystem.ElementXTheme
import io.element.android.x.features.login.error.loginError
import io.element.android.x.matrix.MatrixClient
import timber.log.Timber
@Composable
fun LoginScreen(
viewModel: LoginViewModel = mavericksViewModel(),
onChangeServer: () -> Unit = { },
onLoginWithSuccess: () -> Unit = { },
onLoginWithSuccess: (MatrixClient) -> Unit = { },
) {
val state: LoginViewState by viewModel.collectAsState()
val formState: LoginFormState by viewModel.formState
@ -65,7 +66,7 @@ fun LoginContent( @@ -65,7 +66,7 @@ fun LoginContent(
onLoginChanged: (String) -> Unit = {},
onPasswordChanged: (String) -> Unit = {},
onSubmitClicked: () -> Unit = {},
onLoginWithSuccess: () -> Unit = {},
onLoginWithSuccess: (MatrixClient) -> Unit = {},
) {
Surface(color = MaterialTheme.colorScheme.background) {
Box(
@ -82,7 +83,7 @@ fun LoginContent( @@ -82,7 +83,7 @@ fun LoginContent(
)
.padding(horizontal = 16.dp),
) {
val isError = state.isLoggedIn is Fail
val isError = state.loggedInClient is Fail
// Title
Text(
text = "Welcome back",
@ -137,7 +138,7 @@ fun LoginContent( @@ -137,7 +138,7 @@ fun LoginContent(
),
)
var passwordVisible by remember { mutableStateOf(false) }
if (state.isLoggedIn is Loading) {
if (state.loggedInClient is Loading) {
// Ensure password is hidden when user submits the form
passwordVisible = false
}
@ -170,9 +171,9 @@ fun LoginContent( @@ -170,9 +171,9 @@ fun LoginContent(
onDone = { onSubmitClicked() }
),
)
if (state.isLoggedIn is Fail) {
if (state.loggedInClient is Fail) {
Text(
text = loginError(state.formState, state.isLoggedIn.error),
text = loginError(state.formState, state.loggedInClient.error),
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(start = 16.dp)
@ -189,11 +190,12 @@ fun LoginContent( @@ -189,11 +190,12 @@ fun LoginContent(
) {
Text(text = "Continue")
}
if (state.isLoggedIn is Success) {
onLoginWithSuccess()
when (val loggedInClient = state.loggedInClient) {
is Success -> onLoginWithSuccess(loggedInClient())
else -> Unit
}
}
if (state.isLoggedIn is Loading) {
if (state.loggedInClient is Loading) {
CircularProgressIndicator(
modifier = Modifier.align(Alignment.Center)
)

12
features/login/src/main/java/io/element/android/x/features/login/LoginViewModel.kt

@ -11,7 +11,6 @@ import io.element.android.x.anvilannotations.ContributesViewModel @@ -11,7 +11,6 @@ import io.element.android.x.anvilannotations.ContributesViewModel
import io.element.android.x.core.di.daggerMavericksViewModelFactory
import io.element.android.x.di.AppScope
import io.element.android.x.matrix.Matrix
import io.element.android.x.matrix.MatrixInstance
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@ -49,21 +48,22 @@ class LoginViewModel @AssistedInject constructor( @@ -49,21 +48,22 @@ class LoginViewModel @AssistedInject constructor(
val state = awaitState()
// Ensure the server is provided to the Rust SDK
matrix.setHomeserver(state.homeserver)
matrix.login(state.formState.login.trim(), state.formState.password.trim())
matrix.activeClient().startSync()
matrix.login(state.formState.login.trim(), state.formState.password.trim()).also {
it.startSync()
}
}.execute {
copy(isLoggedIn = it)
copy(loggedInClient = it)
}
}
}
fun onSetPassword(password: String) {
formState.value = formState.value.copy(password = password)
setState { copy(isLoggedIn = Uninitialized) }
setState { copy(loggedInClient = Uninitialized) }
}
fun onSetName(name: String) {
formState.value = formState.value.copy(login = name)
setState { copy(isLoggedIn = Uninitialized) }
setState { copy(loggedInClient = Uninitialized) }
}
}

5
features/login/src/main/java/io/element/android/x/features/login/LoginViewState.kt

@ -4,14 +4,15 @@ import com.airbnb.mvrx.Async @@ -4,14 +4,15 @@ import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksState
import com.airbnb.mvrx.Uninitialized
import io.element.android.x.matrix.MatrixClient
data class LoginViewState(
val homeserver: String = "",
val isLoggedIn: Async<Unit> = Uninitialized,
val loggedInClient: Async<MatrixClient> = Uninitialized,
val formState: LoginFormState = LoginFormState.Default,
) : MavericksState {
val submitEnabled =
formState.login.isNotEmpty() && formState.password.isNotEmpty() && isLoggedIn !is Loading
formState.login.isNotEmpty() && formState.password.isNotEmpty() && loggedInClient !is Loading
}
data class LoginFormState(

19
features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewModel.kt

@ -1,14 +1,25 @@ @@ -1,14 +1,25 @@
package io.element.android.x.features.login.changeserver
import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.MavericksViewModelFactory
import com.airbnb.mvrx.Uninitialized
import io.element.android.x.matrix.MatrixInstance
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.x.anvilannotations.ContributesViewModel
import io.element.android.x.core.di.daggerMavericksViewModelFactory
import io.element.android.x.di.AppScope
import io.element.android.x.matrix.Matrix
import kotlinx.coroutines.launch
class ChangeServerViewModel(initialState: ChangeServerViewState) :
@ContributesViewModel(AppScope::class)
class ChangeServerViewModel @AssistedInject constructor(
private val matrix: Matrix,
@Assisted initialState: ChangeServerViewState
) :
MavericksViewModel<ChangeServerViewState>(initialState) {
private val matrix = MatrixInstance.getInstance()
companion object :
MavericksViewModelFactory<ChangeServerViewModel, ChangeServerViewState> by daggerMavericksViewModelFactory()
init {
setState {
@ -32,7 +43,7 @@ class ChangeServerViewModel(initialState: ChangeServerViewState) : @@ -32,7 +43,7 @@ class ChangeServerViewModel(initialState: ChangeServerViewState) :
suspend {
val state = awaitState()
matrix.setHomeserver(state.homeserver)
}.execute { it ->
}.execute {
copy(changeServerAction = it)
}
}

7
features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt

@ -10,6 +10,7 @@ import io.element.android.x.core.di.daggerMavericksViewModelFactory @@ -10,6 +10,7 @@ import io.element.android.x.core.di.daggerMavericksViewModelFactory
import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.designsystem.components.avatar.AvatarSize
import io.element.android.x.di.AppScope
import io.element.android.x.di.SessionScope
import io.element.android.x.features.messages.model.MessagesItemAction
import io.element.android.x.features.messages.model.MessagesItemActionsSheetState
import io.element.android.x.features.messages.model.MessagesTimelineItemState
@ -17,6 +18,7 @@ import io.element.android.x.features.messages.model.MessagesViewState @@ -17,6 +18,7 @@ import io.element.android.x.features.messages.model.MessagesViewState
import io.element.android.x.features.messages.model.content.MessagesTimelineItemRedactedContent
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent
import io.element.android.x.matrix.Matrix
import io.element.android.x.matrix.MatrixClient
import io.element.android.x.matrix.media.MediaResolver
import io.element.android.x.matrix.timeline.MatrixTimeline
import io.element.android.x.matrix.timeline.MatrixTimelineItem
@ -28,16 +30,15 @@ import kotlinx.coroutines.launch @@ -28,16 +30,15 @@ import kotlinx.coroutines.launch
private const val PAGINATION_COUNT = 50
@ContributesViewModel(AppScope::class)
@ContributesViewModel(SessionScope::class)
class MessagesViewModel @AssistedInject constructor(
matrix: Matrix,
private val client: MatrixClient,
@Assisted private val initialState: MessagesViewState
) :
MavericksViewModel<MessagesViewState>(initialState) {
companion object : MavericksViewModelFactory<MessagesViewModel, MessagesViewState> by daggerMavericksViewModelFactory()
private val client = matrix.activeClient()
private val room = client.getRoom(initialState.roomId)!!
private val messageTimelineItemStateFactory =
MessageTimelineItemStateFactory(client, room, Dispatchers.Default)

10
features/messages/src/main/java/io/element/android/x/features/messages/textcomposer/MessageComposerViewModel.kt

@ -7,20 +7,18 @@ import dagger.assisted.AssistedInject @@ -7,20 +7,18 @@ import dagger.assisted.AssistedInject
import io.element.android.x.anvilannotations.ContributesViewModel
import io.element.android.x.core.data.StableCharSequence
import io.element.android.x.core.di.daggerMavericksViewModelFactory
import io.element.android.x.di.AppScope
import io.element.android.x.matrix.Matrix
import io.element.android.x.di.SessionScope
import io.element.android.x.matrix.MatrixClient
@ContributesViewModel(AppScope::class)
@ContributesViewModel(SessionScope::class)
class MessageComposerViewModel @AssistedInject constructor(
private val matrix: Matrix,
private val client: MatrixClient,
@Assisted private val initialState: MessageComposerViewState
) : MavericksViewModel<MessageComposerViewState>(initialState) {
companion object :
MavericksViewModelFactory<MessageComposerViewModel, MessageComposerViewState> by daggerMavericksViewModelFactory()
private val client = matrix.activeClient()
fun onComposerFullScreenChange() {
setState {
copy(

7
features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt

@ -9,13 +9,13 @@ import io.element.android.x.core.di.daggerMavericksViewModelFactory @@ -9,13 +9,13 @@ import io.element.android.x.core.di.daggerMavericksViewModelFactory
import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.designsystem.components.avatar.AvatarSize
import io.element.android.x.di.AppScope
import io.element.android.x.di.SessionScope
import io.element.android.x.features.roomlist.model.MatrixUser
import io.element.android.x.features.roomlist.model.RoomListRoomSummary
import io.element.android.x.features.roomlist.model.RoomListRoomSummaryPlaceholders
import io.element.android.x.features.roomlist.model.RoomListViewState
import io.element.android.x.matrix.Matrix
import io.element.android.x.matrix.MatrixClient
import io.element.android.x.matrix.MatrixInstance
import io.element.android.x.matrix.media.MediaResolver
import io.element.android.x.matrix.room.RoomSummary
import kotlinx.coroutines.Dispatchers
@ -28,9 +28,9 @@ import kotlinx.coroutines.launch @@ -28,9 +28,9 @@ import kotlinx.coroutines.launch
private const val extendedRangeSize = 40
@ContributesViewModel(AppScope::class)
@ContributesViewModel(SessionScope::class)
class RoomListViewModel @AssistedInject constructor(
matrix: Matrix,
private val client: MatrixClient,
@Assisted initialState: RoomListViewState
) :
MavericksViewModel<RoomListViewState>(initialState) {
@ -38,7 +38,6 @@ class RoomListViewModel @AssistedInject constructor( @@ -38,7 +38,6 @@ class RoomListViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory<RoomListViewModel, RoomListViewState> by daggerMavericksViewModelFactory()
private val lastMessageFormatter = LastMessageFormatter()
private val client = matrix.activeClient()
init {
handleInit()

33
libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt

@ -3,8 +3,8 @@ package io.element.android.x.matrix @@ -3,8 +3,8 @@ package io.element.android.x.matrix
import android.content.Context
import coil.ComponentRegistry
import io.element.android.x.core.coroutine.CoroutineDispatchers
import io.element.android.x.di.ApplicationContext
import io.element.android.x.di.AppScope
import io.element.android.x.di.ApplicationContext
import io.element.android.x.di.SingleIn
import io.element.android.x.matrix.media.MediaFetcher
import io.element.android.x.matrix.media.MediaKeyer
@ -37,35 +37,18 @@ class Matrix @Inject constructor( @@ -37,35 +37,18 @@ class Matrix @Inject constructor(
)
private val baseDirectory = File(context.filesDir, "sessions")
private val sessionStore = SessionStore(context)
private val matrixClient = MutableStateFlow<Optional<MatrixClient>>(Optional.empty())
private val authService = AuthenticationService(baseDirectory.absolutePath)
init {
sessionStore.isLoggedIn()
.distinctUntilChanged()
.onEach { isLoggedIn ->
if (!isLoggedIn) {
matrixClient.value = Optional.empty()
}
}
.launchIn(coroutineScope)
}
fun isLoggedIn(): Flow<Boolean> {
return sessionStore.isLoggedIn()
}
fun client(): Flow<Optional<MatrixClient>> {
return matrixClient
}
fun activeClient(): MatrixClient {
return matrixClient.value.get()
}
fun registerCoilComponents(builder: ComponentRegistry.Builder) {
fun registerCoilComponents(
builder: ComponentRegistry.Builder,
activeClientProvider: () -> MatrixClient?
) {
builder.add(MediaKeyer())
builder.add(MediaFetcher.Factory(this))
builder.add(MediaFetcher.Factory(activeClientProvider))
}
suspend fun restoreSession() = withContext(coroutineDispatchers.io) {
@ -116,8 +99,6 @@ class Matrix @Inject constructor( @@ -116,8 +99,6 @@ class Matrix @Inject constructor(
coroutineScope = coroutineScope,
dispatchers = coroutineDispatchers,
baseDirectory = baseDirectory,
).also {
matrixClient.value = Optional.of(it)
}
)
}
}

6
libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
package io.element.android.x.matrix
import io.element.android.x.core.coroutine.CoroutineDispatchers
import io.element.android.x.di.SingleIn
import io.element.android.x.matrix.core.UserId
import io.element.android.x.matrix.media.MediaResolver
import io.element.android.x.matrix.media.RustMediaResolver
@ -25,6 +26,9 @@ class MatrixClient internal constructor( @@ -25,6 +26,9 @@ class MatrixClient internal constructor(
private val baseDirectory: File,
) : Closeable {
val sessionId: String
get() = "${client.session().userId}_${client.session().deviceId}"
private val clientDelegate = object : ClientDelegate {
override fun didReceiveAuthError(isSoftLogout: Boolean) {
Timber.v("didReceiveAuthError()")
@ -78,7 +82,7 @@ class MatrixClient internal constructor( @@ -78,7 +82,7 @@ class MatrixClient internal constructor(
client.setDelegate(clientDelegate)
}
private fun onRestartSync(){
private fun onRestartSync() {
slidingSyncObserverToken = slidingSync.sync()
}

19
libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixInstance.kt

@ -1,19 +0,0 @@ @@ -1,19 +0,0 @@
package io.element.android.x.matrix
import android.annotation.SuppressLint
import android.app.Application
import kotlinx.coroutines.CoroutineScope
object MatrixInstance {
@SuppressLint("StaticFieldLeak")
private lateinit var instance: Matrix
fun init(context: Application, coroutineScope: CoroutineScope) {
instance = Matrix(coroutineScope, context)
}
fun getInstance(): Matrix {
return instance
}
}

13
libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaFetcher.kt

@ -4,31 +4,32 @@ import coil.ImageLoader @@ -4,31 +4,32 @@ import coil.ImageLoader
import coil.fetch.FetchResult
import coil.fetch.Fetcher
import coil.request.Options
import io.element.android.x.matrix.Matrix
import io.element.android.x.matrix.MatrixClient
import java.nio.ByteBuffer
internal class MediaFetcher(
private val mediaResolver: MediaResolver,
private val mediaResolver: MediaResolver?,
private val meta: MediaResolver.Meta,
private val options: Options,
private val imageLoader: ImageLoader
) : Fetcher {
override suspend fun fetch(): FetchResult? {
val byteArray = mediaResolver.resolve(meta) ?: return null
val byteArray = mediaResolver?.resolve(meta) ?: return null
val byteBuffer = ByteBuffer.wrap(byteArray)
return imageLoader.components.newFetcher(byteBuffer, options, imageLoader)?.first?.fetch()
}
class Factory(private val matrix: Matrix) : Fetcher.Factory<MediaResolver.Meta> {
class Factory(private val activeClientProvider: () -> MatrixClient?) :
Fetcher.Factory<MediaResolver.Meta> {
override fun create(
data: MediaResolver.Meta,
options: Options,
imageLoader: ImageLoader
): Fetcher {
val activeClient = matrix.activeClient()
val activeClient = activeClientProvider()
return MediaFetcher(
mediaResolver = activeClient.mediaResolver(),
mediaResolver = activeClient?.mediaResolver(),
meta = data,
options = options,
imageLoader = imageLoader

Loading…
Cancel
Save