mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-19 18:55:05 +01:00
Lots of progress on new login
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
5e8ab11cbf
commit
7cf1cf6025
@ -159,6 +159,8 @@ ext {
|
||||
lifecycle_version = '2.2.0-rc03'
|
||||
coil_version = "0.9.1"
|
||||
room_version = "2.2.3"
|
||||
geckoviewChannel = "stable"
|
||||
geckoviewVersion = "72.0.20200107212822"
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
@ -185,6 +187,7 @@ dependencies {
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
|
||||
implementation "org.mozilla.geckoview:geckoview:${geckoviewVersion}"
|
||||
implementation "com.github.stateless4j:stateless4j:2.6.0"
|
||||
|
||||
// ViewModel and LiveData
|
||||
|
@ -26,8 +26,6 @@ import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.emoji.widget.EmojiTextView
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import coil.api.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.nextcloud.talk.R
|
||||
|
@ -181,7 +181,7 @@ class NextcloudTalkApplication : Application(), LifecycleObserver {
|
||||
startKoin {
|
||||
androidContext(this@NextcloudTalkApplication)
|
||||
androidLogger()
|
||||
modules(listOf(CommunicationModule, StorageModule, NetworkModule, ConversationsModule, ConversationsListModule, ServiceModule, AccountModule, ServerModule))
|
||||
modules(listOf(CommunicationModule, StorageModule, NetworkModule, ConversationsListModule, ServiceModule, AccountModule, ServerModule))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
package com.nextcloud.talk.controllers
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
@ -113,6 +114,7 @@ class AccountVerificationController(args: Bundle?) : BaseController(), KoinCompo
|
||||
eventBus.register(this)
|
||||
}
|
||||
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
override fun onViewBound(view: View) {
|
||||
super.onViewBound(view)
|
||||
if (activity != null) {
|
||||
@ -257,16 +259,11 @@ class AccountVerificationController(args: Bundle?) : BaseController(), KoinCompo
|
||||
override fun onSubscribe(d: Disposable) {}
|
||||
|
||||
override fun onNext(userProfileOverall: UserProfileOverall) {
|
||||
var displayName: String? = null
|
||||
if (!TextUtils.isEmpty(userProfileOverall.ocs.data.displayName)) {
|
||||
displayName = userProfileOverall.ocs.data.displayName
|
||||
} else if (!TextUtils.isEmpty(userProfileOverall.ocs.data.displayNameAlt)) {
|
||||
displayName = userProfileOverall.ocs.data.displayNameAlt
|
||||
}
|
||||
var displayName: String? = userProfileOverall.ocs.data.displayName
|
||||
|
||||
if (!TextUtils.isEmpty(displayName)) {
|
||||
GlobalScope.launch {
|
||||
storeProfile(displayName, userProfileOverall.ocs.data.userId)
|
||||
storeProfile(displayName, userProfileOverall.ocs.data.userId!!)
|
||||
}
|
||||
} else {
|
||||
if (activity != null) {
|
||||
|
@ -900,22 +900,22 @@ class CallController(args: Bundle) : BaseController() {
|
||||
override fun onNext(signalingSettingsOverall: SignalingSettingsOverall) {
|
||||
var iceServer: IceServer
|
||||
if (signalingSettingsOverall.ocs != null &&
|
||||
signalingSettingsOverall.ocs.settings != null
|
||||
signalingSettingsOverall.ocs.signalingSettings != null
|
||||
) {
|
||||
|
||||
externalSignalingServer = ExternalSignalingServer()
|
||||
|
||||
if (!TextUtils.isEmpty(
|
||||
signalingSettingsOverall.ocs.settings.externalSignalingServer
|
||||
signalingSettingsOverall.ocs.signalingSettings.externalSignalingServer
|
||||
) && !TextUtils.isEmpty(
|
||||
signalingSettingsOverall.ocs
|
||||
.settings
|
||||
.signalingSettings
|
||||
.externalSignalingTicket
|
||||
)
|
||||
) {
|
||||
externalSignalingServer = ExternalSignalingServer()
|
||||
externalSignalingServer!!.externalSignalingServer = signalingSettingsOverall.ocs.settings.externalSignalingServer
|
||||
externalSignalingServer!!.externalSignalingTicket = signalingSettingsOverall.ocs.settings.externalSignalingTicket
|
||||
externalSignalingServer!!.externalSignalingServer = signalingSettingsOverall.ocs.signalingSettings.externalSignalingServer
|
||||
externalSignalingServer!!.externalSignalingTicket = signalingSettingsOverall.ocs.signalingSettings.externalSignalingTicket
|
||||
hasExternalSignalingServer = true
|
||||
} else {
|
||||
hasExternalSignalingServer = false
|
||||
@ -936,9 +936,9 @@ class CallController(args: Bundle) : BaseController() {
|
||||
|
||||
}
|
||||
|
||||
if (signalingSettingsOverall.ocs.settings.stunServers != null) {
|
||||
for (i in 0 until signalingSettingsOverall.ocs.settings.stunServers.size) {
|
||||
iceServer = signalingSettingsOverall.ocs.settings.stunServers[i]
|
||||
if (signalingSettingsOverall.ocs.signalingSettings.stunServers != null) {
|
||||
for (i in 0 until signalingSettingsOverall.ocs.signalingSettings.stunServers!!.size) {
|
||||
iceServer = signalingSettingsOverall.ocs.signalingSettings.stunServers!![i]
|
||||
if (TextUtils.isEmpty(iceServer.username) || TextUtils.isEmpty(
|
||||
iceServer
|
||||
.credential
|
||||
@ -956,20 +956,20 @@ class CallController(args: Bundle) : BaseController() {
|
||||
}
|
||||
}
|
||||
|
||||
if (signalingSettingsOverall.ocs.settings.turnServers != null) {
|
||||
for (i in 0 until signalingSettingsOverall.ocs.settings.turnServers.size) {
|
||||
iceServer = signalingSettingsOverall.ocs.settings.turnServers[i]
|
||||
for (j in 0 until iceServer.urls.size) {
|
||||
if (signalingSettingsOverall.ocs.signalingSettings.turnServers != null) {
|
||||
for (i in 0 until signalingSettingsOverall.ocs.signalingSettings.turnServers!!.size) {
|
||||
iceServer = signalingSettingsOverall.ocs.signalingSettings.turnServers!![i]
|
||||
for (j in 0 until iceServer.urls!!.size) {
|
||||
if (TextUtils.isEmpty(iceServer.username) || TextUtils.isEmpty(
|
||||
iceServer
|
||||
.credential
|
||||
)
|
||||
) {
|
||||
iceServers!!.add(PeerConnection.IceServer(iceServer.urls[j]))
|
||||
iceServers!!.add(PeerConnection.IceServer(iceServer.urls!![j]))
|
||||
} else {
|
||||
iceServers!!.add(
|
||||
PeerConnection.IceServer(
|
||||
iceServer.urls[j],
|
||||
iceServer.urls!![j],
|
||||
iceServer.username, iceServer.credential
|
||||
)
|
||||
)
|
||||
|
@ -26,7 +26,6 @@ import androidx.work.WorkManager
|
||||
import androidx.work.WorkerParameters
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.events.EventStatus
|
||||
import com.nextcloud.talk.jobs.WebsocketConnectionsWorker
|
||||
import com.nextcloud.talk.models.ExternalSignalingServer
|
||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
|
||||
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
|
||||
@ -69,8 +68,8 @@ class SignalingSettingsWorker(context: Context, workerParams: WorkerParameters)
|
||||
override fun onNext(signalingSettingsOverall: SignalingSettingsOverall) {
|
||||
val externalSignalingServer: ExternalSignalingServer
|
||||
externalSignalingServer = ExternalSignalingServer()
|
||||
externalSignalingServer.externalSignalingServer = signalingSettingsOverall.ocs.settings.externalSignalingServer
|
||||
externalSignalingServer.externalSignalingTicket = signalingSettingsOverall.ocs.settings.externalSignalingTicket
|
||||
externalSignalingServer.externalSignalingServer = signalingSettingsOverall.ocs.signalingSettings.externalSignalingServer
|
||||
externalSignalingServer.externalSignalingTicket = signalingSettingsOverall.ocs.signalingSettings.externalSignalingTicket
|
||||
val user = usersRepository.getUserWithId(userEntity.id!!)
|
||||
user.externalSignaling = externalSignalingServer
|
||||
runBlocking {
|
||||
|
@ -17,28 +17,30 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.talk.models.json.signaling.settings
|
||||
|
||||
package com.nextcloud.talk.models.json.signaling.settings;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import android.os.Parcelable
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
import lombok.Data
|
||||
|
||||
@Data
|
||||
@JsonObject
|
||||
public class IceServer {
|
||||
@JsonField(name = "url")
|
||||
public String url;
|
||||
|
||||
@JsonField(name = "urls")
|
||||
public List<String> urls;
|
||||
|
||||
@JsonField(name = "username")
|
||||
public String username;
|
||||
|
||||
@JsonField(name = "credential")
|
||||
public String credential;
|
||||
}
|
||||
@Parcelize
|
||||
@Serializable
|
||||
data class IceServer @JvmOverloads constructor(
|
||||
@JvmField
|
||||
@JsonField(name = ["url"])
|
||||
var url: String? = null,
|
||||
@JvmField
|
||||
@JsonField(name = ["urls"])
|
||||
var urls: List<String>? = null,
|
||||
@JvmField
|
||||
@JsonField(name = ["username"])
|
||||
var username: String? = null,
|
||||
@JvmField
|
||||
@JsonField(name = ["credential"])
|
||||
var credential: String? = null
|
||||
) : Parcelable
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.models.json.signaling.settings;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonObject
|
||||
public class Settings {
|
||||
@JsonField(name = "stunservers")
|
||||
public List<IceServer> stunServers;
|
||||
|
||||
@JsonField(name = "turnservers")
|
||||
public List<IceServer> turnServers;
|
||||
|
||||
@JsonField(name = "server")
|
||||
public String externalSignalingServer;
|
||||
|
||||
@JsonField(name = "ticket")
|
||||
public String externalSignalingTicket;
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.talk.models.json.signaling.settings
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
import lombok.Data
|
||||
|
||||
@Data
|
||||
@JsonObject
|
||||
@Serializable
|
||||
@Parcelize
|
||||
data class SignalingSettings @JvmOverloads constructor(
|
||||
@JvmField
|
||||
@JsonField(name = ["stunservers"])
|
||||
var stunServers: List<IceServer>? = null,
|
||||
@JvmField
|
||||
@JsonField(name = ["turnservers"])
|
||||
var turnServers: List<IceServer>? = null,
|
||||
@JvmField
|
||||
@JsonField(name = ["server"])
|
||||
var externalSignalingServer: String? = null,
|
||||
@JvmField
|
||||
@JsonField(name = ["ticket"])
|
||||
var externalSignalingTicket: String? = null
|
||||
) : Parcelable
|
@ -30,5 +30,5 @@ import lombok.Data;
|
||||
@JsonObject
|
||||
public class SignalingSettingsOcs extends GenericOCS {
|
||||
@JsonField(name = "data")
|
||||
public Settings settings;
|
||||
public SignalingSettings signalingSettings;
|
||||
}
|
||||
|
@ -18,25 +18,21 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.talk.models.json.userprofile;
|
||||
package com.nextcloud.talk.models.json.userprofile
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
|
||||
import org.parceler.Parcel;
|
||||
|
||||
import lombok.Data;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
import lombok.Data
|
||||
import org.parceler.Parcel
|
||||
|
||||
@Parcel
|
||||
@Data
|
||||
@JsonObject
|
||||
public class UserProfileData {
|
||||
@JsonField(name = "display-name")
|
||||
public String displayName;
|
||||
|
||||
@JsonField(name = "displayname")
|
||||
public String displayNameAlt;
|
||||
|
||||
@JsonField(name = "id")
|
||||
public String userId;
|
||||
}
|
||||
class UserProfileData {
|
||||
@JvmField
|
||||
@JsonField(name = ["display-name", "displayname"])
|
||||
var displayName: String? = null
|
||||
@JvmField
|
||||
@JsonField(name = ["id"])
|
||||
var userId: String? = null
|
||||
}
|
@ -24,6 +24,9 @@ import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||
import com.nextcloud.talk.models.json.push.PushRegistrationOverall
|
||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
|
||||
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
|
||||
import com.nextcloud.talk.newarch.data.source.remote.ApiService
|
||||
import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkRepository
|
||||
import com.nextcloud.talk.newarch.local.models.UserNgEntity
|
||||
@ -86,6 +89,30 @@ class NextcloudTalkRepositoryImpl(private val apiService: ApiService) : Nextclou
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun registerPushWithServerForUser(user: UserNgEntity, options: Map<String, String>): PushRegistrationOverall {
|
||||
return apiService.registerForPushWithServer(user.getCredentials(), ApiUtils.getUrlNextcloudPush(user.baseUrl), options)
|
||||
}
|
||||
|
||||
override suspend fun unregisterPushWithServerForUser(user: UserNgEntity): GenericOverall {
|
||||
return apiService.unregisterForPushWithServer(user.getCredentials(), ApiUtils.getUrlNextcloudPush(user.baseUrl))
|
||||
}
|
||||
|
||||
override suspend fun registerPushWithProxyForUser(user: UserNgEntity, options: Map<String, String>): Any {
|
||||
return apiService.unregisterForPushWithProxy(ApiUtils.getUrlPushProxy(), options)
|
||||
}
|
||||
|
||||
override suspend fun unregisterPushWithProxyForUser(user: UserNgEntity, options: Map<String, String>): Any {
|
||||
return apiService.unregisterForPushWithProxy(ApiUtils.getUrlPushProxy(), options)
|
||||
}
|
||||
|
||||
override suspend fun getSignalingSettingsForUser(user: UserNgEntity): SignalingSettingsOverall {
|
||||
return apiService.getSignalingSettings(user.getCredentials(), ApiUtils.getUrlForSignalingSettings(user.baseUrl))
|
||||
}
|
||||
|
||||
override suspend fun getProfileForUser(user: UserNgEntity): UserProfileOverall {
|
||||
return apiService.getUserProfile(user.getCredentials(), ApiUtils.getUrlForUserProfile(user.baseUrl))
|
||||
}
|
||||
|
||||
override suspend fun getConversationsForUser(user: UserNgEntity): List<Conversation> {
|
||||
return apiService.getConversations(
|
||||
user.getCredentials(),
|
||||
|
@ -24,16 +24,59 @@ import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.conversations.RoomsOverall
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||
import com.nextcloud.talk.models.json.push.PushRegistrationOverall
|
||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
|
||||
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
|
||||
import io.reactivex.Observable
|
||||
import retrofit2.http.*
|
||||
|
||||
interface ApiService {
|
||||
|
||||
/*
|
||||
Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /room
|
||||
*/
|
||||
@GET
|
||||
suspend fun getCapabilities(@Url url: String): CapabilitiesOverall
|
||||
|
||||
@GET
|
||||
suspend fun getSignalingSettings(@Header("Authorization") authorization: String,
|
||||
@Url url: String): SignalingSettingsOverall
|
||||
|
||||
@GET
|
||||
suspend fun getUserProfile(@Header("Authorization") authorization: String,
|
||||
@Url url: String): UserProfileOverall
|
||||
|
||||
/*
|
||||
QueryMap items are as follows:
|
||||
- "format" : "json"
|
||||
- "pushTokenHash" : ""
|
||||
- "devicePublicKey" : ""
|
||||
- "proxyServer" : ""
|
||||
|
||||
Server URL is: baseUrl + ocsApiVersion + "/apps/notifications/api/v2/push
|
||||
*/
|
||||
@POST
|
||||
fun registerForPushWithServer(
|
||||
@Header("Authorization") authorization: String,
|
||||
@Url url: String,
|
||||
@QueryMap options: Map<String, String>): PushRegistrationOverall
|
||||
|
||||
@DELETE
|
||||
fun unregisterForPushWithServer(@Header("Authorization") authorization: String,
|
||||
@Url url: String): GenericOverall
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST
|
||||
fun registerForPushWithProxy(@Url url: String,
|
||||
@FieldMap fields: Map<String, String>): Any
|
||||
|
||||
/*
|
||||
QueryMap items are as follows:
|
||||
- "deviceIdentifier": "{{deviceIdentifier}}",
|
||||
- "deviceIdentifierSignature": "{{signature}}",
|
||||
- "userPublicKey": "{{userPublicKey}}"
|
||||
*/
|
||||
@DELETE
|
||||
fun unregisterForPushWithProxy(@Url url: String?,
|
||||
@QueryMap fields: Map<String, String>): Any
|
||||
|
||||
@GET
|
||||
suspend fun getConversations(
|
||||
@Header(
|
||||
|
@ -1,70 +0,0 @@
|
||||
package com.nextcloud.talk.newarch.di.module
|
||||
|
||||
import android.app.Application
|
||||
import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
|
||||
import com.nextcloud.talk.newarch.domain.repository.offline.ConversationsRepository
|
||||
import com.nextcloud.talk.newarch.domain.repository.offline.MessagesRepository
|
||||
import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkRepository
|
||||
import com.nextcloud.talk.newarch.domain.usecases.*
|
||||
import com.nextcloud.talk.newarch.features.chat.ChatViewModelFactory
|
||||
import com.nextcloud.talk.newarch.services.GlobalService
|
||||
import org.koin.dsl.module
|
||||
|
||||
val ConversationsModule = module {
|
||||
single { createGetConversationUseCase(get(), get()) }
|
||||
single { createGetConversationsUseCase(get(), get()) }
|
||||
single { createSetConversationFavoriteValueUseCase(get(), get()) }
|
||||
single { createLeaveConversationUseCase(get(), get()) }
|
||||
single { createDeleteConversationUseCase(get(), get()) }
|
||||
single { createJoinConversationUseCase(get(), get()) }
|
||||
single { createExitConversationUseCase(get(), get()) }
|
||||
factory { createChatViewModelFactory(get(), get(), get(), get(), get(), get()) }
|
||||
}
|
||||
|
||||
|
||||
fun createSetConversationFavoriteValueUseCase(
|
||||
nextcloudTalkRepository: NextcloudTalkRepository,
|
||||
apiErrorHandler: ApiErrorHandler
|
||||
): SetConversationFavoriteValueUseCase {
|
||||
return SetConversationFavoriteValueUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||
}
|
||||
|
||||
fun createGetConversationUseCase(
|
||||
nextcloudTalkRepository: NextcloudTalkRepository,
|
||||
apiErrorHandler: ApiErrorHandler
|
||||
): GetConversationUseCase {
|
||||
return GetConversationUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||
}
|
||||
|
||||
fun createGetConversationsUseCase(
|
||||
nextcloudTalkRepository: NextcloudTalkRepository,
|
||||
apiErrorHandler: ApiErrorHandler
|
||||
): GetConversationsUseCase {
|
||||
return GetConversationsUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||
}
|
||||
|
||||
fun createLeaveConversationUseCase(
|
||||
nextcloudTalkRepository: NextcloudTalkRepository,
|
||||
apiErrorHandler: ApiErrorHandler
|
||||
): LeaveConversationUseCase {
|
||||
return LeaveConversationUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||
}
|
||||
|
||||
fun createDeleteConversationUseCase(
|
||||
nextcloudTalkRepository: NextcloudTalkRepository,
|
||||
apiErrorHandler: ApiErrorHandler
|
||||
): DeleteConversationUseCase {
|
||||
return DeleteConversationUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||
}
|
||||
|
||||
fun createJoinConversationUseCase(nextcloudTalkRepository: NextcloudTalkRepository, apiErrorHandler: ApiErrorHandler): JoinConversationUseCase {
|
||||
return JoinConversationUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||
}
|
||||
|
||||
fun createExitConversationUseCase(nextcloudTalkRepository: NextcloudTalkRepository, apiErrorHandler: ApiErrorHandler): ExitConversationUseCase {
|
||||
return ExitConversationUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||
}
|
||||
|
||||
fun createChatViewModelFactory(application: Application, joinConversationUseCase: JoinConversationUseCase, exitConversationUseCase: ExitConversationUseCase, conversationsRepository: ConversationsRepository, messagesRepository: MessagesRepository, globalService: GlobalService): ChatViewModelFactory {
|
||||
return ChatViewModelFactory(application, joinConversationUseCase, exitConversationUseCase, conversationsRepository, messagesRepository, globalService)
|
||||
}
|
@ -3,14 +3,22 @@ package com.nextcloud.talk.newarch.di.module
|
||||
import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
|
||||
import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkRepository
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetCapabilitiesUseCase
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetSignalingSettingsUseCase
|
||||
import org.koin.dsl.module
|
||||
|
||||
val ServerModule = module {
|
||||
single { createGetCapabilitiesUseCase(get(), get()) }
|
||||
single { createGetSignalingSettingsUseCase(get(), get()) }
|
||||
}
|
||||
|
||||
fun createGetCapabilitiesUseCase(nextcloudTalkRepository: NextcloudTalkRepository,
|
||||
apiErrorHandler: ApiErrorHandler
|
||||
): GetCapabilitiesUseCase {
|
||||
return GetCapabilitiesUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||
}
|
||||
|
||||
fun createGetSignalingSettingsUseCase(nextcloudTalkRepository: NextcloudTalkRepository,
|
||||
apiErrorHandler: ApiErrorHandler
|
||||
): GetSignalingSettingsUseCase {
|
||||
return GetSignalingSettingsUseCase(nextcloudTalkRepository, apiErrorHandler)
|
||||
}
|
@ -24,9 +24,19 @@ import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||
import com.nextcloud.talk.models.json.push.PushRegistrationOverall
|
||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
|
||||
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
|
||||
import com.nextcloud.talk.newarch.local.models.UserNgEntity
|
||||
|
||||
interface NextcloudTalkRepository {
|
||||
suspend fun registerPushWithServerForUser(user: UserNgEntity, options: Map<String, String>): PushRegistrationOverall
|
||||
suspend fun unregisterPushWithServerForUser(user: UserNgEntity): GenericOverall
|
||||
suspend fun registerPushWithProxyForUser(user: UserNgEntity, options: Map<String, String>): Any
|
||||
suspend fun unregisterPushWithProxyForUser(user: UserNgEntity, options: Map<String, String>): Any
|
||||
|
||||
suspend fun getSignalingSettingsForUser(user: UserNgEntity): SignalingSettingsOverall
|
||||
suspend fun getProfileForUser(user: UserNgEntity): UserProfileOverall
|
||||
suspend fun getConversationsForUser(user: UserNgEntity): List<Conversation>
|
||||
suspend fun setFavoriteValueForConversation(
|
||||
user: UserNgEntity,
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.newarch.domain.usecases
|
||||
|
||||
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
|
||||
import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
|
||||
import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkRepository
|
||||
import com.nextcloud.talk.newarch.domain.usecases.base.UseCase
|
||||
import org.koin.core.parameter.DefinitionParameters
|
||||
|
||||
class GetProfileUseCase constructor(
|
||||
private val nextcloudTalkRepository: NextcloudTalkRepository,
|
||||
apiErrorHandler: ApiErrorHandler?
|
||||
) : UseCase<UserProfileOverall, Any?>(apiErrorHandler) {
|
||||
override suspend fun run(params: Any?): UserProfileOverall {
|
||||
val definitionParameters = params as DefinitionParameters
|
||||
return nextcloudTalkRepository.getProfileForUser(definitionParameters[0])
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.newarch.domain.usecases
|
||||
|
||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
|
||||
import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
|
||||
import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkRepository
|
||||
import com.nextcloud.talk.newarch.domain.usecases.base.UseCase
|
||||
import org.koin.core.parameter.DefinitionParameters
|
||||
|
||||
class GetSignalingSettingsUseCase constructor(
|
||||
private val nextcloudTalkRepository: NextcloudTalkRepository,
|
||||
apiErrorHandler: ApiErrorHandler?
|
||||
) : UseCase<SignalingSettingsOverall, Any?>(apiErrorHandler) {
|
||||
override suspend fun run(params: Any?): SignalingSettingsOverall {
|
||||
val definitionParameters = params as DefinitionParameters
|
||||
return nextcloudTalkRepository.getSignalingSettingsForUser(definitionParameters[0])
|
||||
}
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
package com.nextcloud.talk.newarch.features.account.di.module
|
||||
|
||||
import android.app.Application
|
||||
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetCapabilitiesUseCase
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetProfileUseCase
|
||||
import com.nextcloud.talk.newarch.features.account.loginentry.LoginEntryViewModelFactory
|
||||
import com.nextcloud.talk.newarch.features.account.serverentry.ServerEntryViewModelFactory
|
||||
import org.koin.android.ext.koin.androidApplication
|
||||
import org.koin.dsl.module
|
||||
@ -12,6 +15,9 @@ val AccountModule = module {
|
||||
androidApplication(), get()
|
||||
)
|
||||
}
|
||||
factory {
|
||||
createLoginEntryViewModelFactory(androidApplication(), get(), get(), get())
|
||||
}
|
||||
}
|
||||
|
||||
fun createServerEntryViewModelFactory(
|
||||
@ -21,4 +27,15 @@ fun createServerEntryViewModelFactory(
|
||||
return ServerEntryViewModelFactory(
|
||||
application, getCapabilitiesUseCase
|
||||
)
|
||||
}
|
||||
|
||||
fun createLoginEntryViewModelFactory(
|
||||
application: Application,
|
||||
getProfileUseCase: GetProfileUseCase,
|
||||
getCapabilitiesUseCase: GetCapabilitiesUseCase,
|
||||
usersRepository: UsersRepository
|
||||
): LoginEntryViewModelFactory {
|
||||
return LoginEntryViewModelFactory(
|
||||
application, getProfileUseCase, getCapabilitiesUseCase, usersRepository
|
||||
)
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.newarch.features.account.loginentry
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
enum class LoginEntryState {
|
||||
PENDING_CHECK,
|
||||
CHECKING,
|
||||
FAILED,
|
||||
OK
|
||||
}
|
||||
|
||||
enum class LoginEntryStateClarification {
|
||||
INVALID_PARSED_DATA,
|
||||
PROFILE_FETCH_FAILED,
|
||||
CAPABILITIES_FETCH_FAILED,
|
||||
SIGNALING_SETTINGS_FETCH_FAILED,
|
||||
PUSH_REGISTRATION_MISSING_TOKEN,
|
||||
PUSH_REGISTRATION_WITH_SERVER_FAILED,
|
||||
PUSH_REGISTRATION_WITH_PUSH_PROXY_FAILED,
|
||||
ACCOUNT_UPDATED,
|
||||
ACCOUNT_CREATED
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class LoginEntryStateWrapper(val state: LoginEntryState, val clarification: LoginEntryStateClarification?)
|
@ -0,0 +1,143 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.newarch.features.account.loginentry
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.newarch.conversationsList.mvp.BaseView
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||
import kotlinx.android.synthetic.main.login_entry_view.view.*
|
||||
import kotlinx.android.synthetic.main.login_web_view.view.*
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.mozilla.geckoview.*
|
||||
import org.mozilla.geckoview.GeckoSessionSettings.USER_AGENT_MODE_MOBILE
|
||||
import java.util.*
|
||||
|
||||
class LoginEntryView(val bundle: Bundle) : BaseView() {
|
||||
private val protocolSuffix = "://"
|
||||
private val dataSeparator = ":"
|
||||
|
||||
private lateinit var viewModel: LoginEntryViewModel
|
||||
val factory: LoginEntryViewModelFactory by inject()
|
||||
|
||||
private lateinit var geckoView: GeckoView
|
||||
private lateinit var geckoSession: GeckoSession
|
||||
|
||||
private val assembledPrefix = resources?.getString(R.string.nc_talk_login_scheme) + protocolSuffix + "login/"
|
||||
|
||||
private val webLoginUserAgent: String
|
||||
get() = (Build.MANUFACTURER.substring(0, 1).toUpperCase(
|
||||
Locale.getDefault()) +
|
||||
Build.MANUFACTURER.substring(1).toLowerCase(
|
||||
Locale.getDefault()) + " " + Build.MODEL + " ("
|
||||
+ resources!!.getString(R.string.nc_app_name) + ")")
|
||||
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.login_entry_view
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
actionBar?.hide()
|
||||
viewModel = viewModelProvider(factory).get(LoginEntryViewModel::class.java)
|
||||
val view = super.onCreateView(inflater, container)
|
||||
|
||||
geckoView = view.stubImport.inflate() as GeckoView
|
||||
activity?.let {
|
||||
val settings = GeckoSessionSettings.Builder()
|
||||
//.usePrivateMode(true)
|
||||
//.useTrackingProtection(true)
|
||||
.userAgentMode(USER_AGENT_MODE_MOBILE)
|
||||
.userAgentOverride(webLoginUserAgent)
|
||||
.suspendMediaWhenInactive(true)
|
||||
.allowJavascript(true)
|
||||
|
||||
geckoView.autofillEnabled = true
|
||||
geckoSession = GeckoSession(settings.build())
|
||||
val runtime = GeckoRuntime.create(it)
|
||||
geckoSession.open(runtime)
|
||||
geckoSession.progressDelegate = createProgressDelegate()
|
||||
geckoSession.navigationDelegate = createNavigationDelegate()
|
||||
geckoView.setSession(geckoSession)
|
||||
bundle.getString(BundleKeys.KEY_BASE_URL)?.let { baseUrl ->
|
||||
geckoSession.loadUri("$baseUrl/index.php/login/flow", mapOf<String, String>("OCS-APIRequest" to "true"))
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.state.observe(this@LoginEntryView, Observer {
|
||||
if (it.state == LoginEntryState.FAILED) {
|
||||
router.popController(this)
|
||||
} else if (it.state == LoginEntryState.PENDING_CHECK) {
|
||||
view.progressBar.isVisible = false
|
||||
view.geckoView.isVisible = true
|
||||
} else if (it.state == LoginEntryState.CHECKING) {
|
||||
view.progressBar.isVisible = true
|
||||
view.geckoView.isVisible = false
|
||||
} else {
|
||||
// all good, proceed
|
||||
}
|
||||
})
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private fun createNavigationDelegate(): GeckoSession.NavigationDelegate {
|
||||
return object : GeckoSession.NavigationDelegate {
|
||||
override fun onLoadRequest(p0: GeckoSession, p1: GeckoSession.NavigationDelegate.LoadRequest): GeckoResult<AllowOrDeny>? {
|
||||
if (p1.uri.startsWith(assembledPrefix)) {
|
||||
return GeckoResult.DENY
|
||||
}
|
||||
return super.onLoadRequest(p0, p1)
|
||||
}
|
||||
|
||||
override fun onLocationChange(p0: GeckoSession, p1: String?) {
|
||||
super.onLocationChange(p0, p1)
|
||||
viewModel.parseData(assembledPrefix, dataSeparator, p1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createProgressDelegate(): GeckoSession.ProgressDelegate {
|
||||
return object : GeckoSession.ProgressDelegate {
|
||||
|
||||
override fun onPageStop(session: GeckoSession, success: Boolean) = Unit
|
||||
|
||||
override fun onSecurityChange(
|
||||
session: GeckoSession,
|
||||
securityInfo: GeckoSession.ProgressDelegate.SecurityInformation
|
||||
) = Unit
|
||||
|
||||
override fun onPageStart(session: GeckoSession, url: String) = Unit
|
||||
|
||||
override fun onProgressChange(session: GeckoSession, progress: Int) {
|
||||
view?.pageProgressBar?.progress = progress
|
||||
view?.pageProgressBar?.isVisible = progress in 1..99
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
package com.nextcloud.talk.newarch.features.account.loginentry
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.nextcloud.talk.models.LoginData
|
||||
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
|
||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
|
||||
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
|
||||
import com.nextcloud.talk.newarch.conversationsList.mvp.BaseViewModel
|
||||
import com.nextcloud.talk.newarch.data.model.ErrorModel
|
||||
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetCapabilitiesUseCase
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetProfileUseCase
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetSignalingSettingsUseCase
|
||||
import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse
|
||||
import com.nextcloud.talk.newarch.local.models.UserNgEntity
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import java.net.URLDecoder
|
||||
|
||||
class LoginEntryViewModel constructor(
|
||||
application: Application,
|
||||
private val getProfileUseCase: GetProfileUseCase,
|
||||
private val getCapabilitiesUseCase: GetCapabilitiesUseCase,
|
||||
private val getSignalingSettingsUseCase: GetSignalingSettingsUseCase,
|
||||
private val appPreferences: AppPreferences,
|
||||
private val usersRepository: UsersRepository) :
|
||||
BaseViewModel<LoginEntryView>(application) {
|
||||
val state: MutableLiveData<LoginEntryStateWrapper> = MutableLiveData(LoginEntryStateWrapper(LoginEntryState.PENDING_CHECK, null))
|
||||
|
||||
private val user = UserNgEntity(-1, "-1", "", "")
|
||||
|
||||
fun parseData(prefix: String, separator: String, data: String?) {
|
||||
viewModelScope.launch {
|
||||
if (data?.startsWith(prefix) == false) {
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.FAILED, LoginEntryStateClarification.INVALID_PARSED_DATA))
|
||||
return@launch
|
||||
}
|
||||
|
||||
data as String
|
||||
|
||||
val loginData = LoginData()
|
||||
// format is xxx://login/server:xxx&user:xxx&password:xxx
|
||||
val dataWithoutPrefix = data.substring(prefix.length)
|
||||
val values = dataWithoutPrefix.split("&").toTypedArray()
|
||||
if (values.size != 3) {
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.FAILED, LoginEntryStateClarification.INVALID_PARSED_DATA))
|
||||
return@launch
|
||||
}
|
||||
|
||||
for (value in values) {
|
||||
when {
|
||||
value.startsWith("user$separator") -> {
|
||||
loginData.username = URLDecoder.decode(
|
||||
value.substring("user$separator".length)
|
||||
)
|
||||
}
|
||||
value.startsWith("password$separator") -> {
|
||||
loginData.token = URLDecoder.decode(
|
||||
value.substring("password$separator".length)
|
||||
)
|
||||
}
|
||||
value.startsWith("server$separator") -> {
|
||||
loginData.serverUrl = URLDecoder.decode(
|
||||
value.substring("server$separator".length)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
// fail
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.FAILED, LoginEntryStateClarification.INVALID_PARSED_DATA))
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!loginData.serverUrl.isNullOrEmpty() && !loginData.username.isNullOrEmpty() && !loginData.token.isNullOrEmpty()) {
|
||||
storeCredentialsOrVerify(loginData)
|
||||
} else {
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.FAILED, LoginEntryStateClarification.INVALID_PARSED_DATA))
|
||||
return@launch
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun storeCredentialsOrVerify(loginData: LoginData) {
|
||||
// username and server url will be null here for sure because we do a check earlier in the process
|
||||
val user = usersRepository.getUserWithUsernameAndServer(loginData.username!!, loginData.serverUrl!!)
|
||||
if (user != null) {
|
||||
user.token = loginData.token
|
||||
usersRepository.updateUser(user)
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.OK, LoginEntryStateClarification.ACCOUNT_UPDATED))
|
||||
} else {
|
||||
getProfile(loginData)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getProfile(loginData: LoginData) {
|
||||
user.username = loginData.username!!
|
||||
user.baseUrl = loginData.serverUrl!!
|
||||
getProfileUseCase.invoke(viewModelScope, parametersOf(user), object : UseCaseResponse<UserProfileOverall> {
|
||||
override suspend fun onSuccess(result: UserProfileOverall) {
|
||||
result.ocs.data.userId?.let { userId ->
|
||||
user.displayName = result.ocs.data.displayName
|
||||
user.userId = userId
|
||||
getCapabilities()
|
||||
} ?: run {
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.FAILED, LoginEntryStateClarification.PROFILE_FETCH_FAILED))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun onError(errorModel: ErrorModel?) {
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.FAILED, LoginEntryStateClarification.PROFILE_FETCH_FAILED))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun getCapabilities() {
|
||||
getCapabilitiesUseCase.invoke(viewModelScope, parametersOf(user.baseUrl), object : UseCaseResponse<CapabilitiesOverall> {
|
||||
override suspend fun onSuccess(result: CapabilitiesOverall) {
|
||||
user.capabilities = result.ocs.data.capabilities
|
||||
getSignalingSettings()
|
||||
}
|
||||
|
||||
override suspend fun onError(errorModel: ErrorModel?) {
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.FAILED, LoginEntryStateClarification.CAPABILITIES_FETCH_FAILED))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun getSignalingSettings() {
|
||||
getSignalingSettingsUseCase.invoke(viewModelScope, parametersOf(user), object : UseCaseResponse<SignalingSettingsOverall> {
|
||||
override suspend fun onSuccess(result: SignalingSettingsOverall) {
|
||||
user.signalingSettings = result.ocs.signalingSettings
|
||||
registerForPush()
|
||||
}
|
||||
|
||||
override suspend fun onError(errorModel: ErrorModel?) {
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.FAILED, LoginEntryStateClarification.SIGNALING_SETTINGS_FETCH_FAILED))
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private fun registerForPush() {
|
||||
val token = appPreferences.pushToken
|
||||
if (!token.isNullOrBlank()) {
|
||||
|
||||
} else {
|
||||
state.postValue(LoginEntryStateWrapper(LoginEntryState.OK, LoginEntryStateClarification.PUSH_REGISTRATION_MISSING_TOKEN))
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerForPushWithServer() {
|
||||
|
||||
}
|
||||
|
||||
private fun registerForPushWithProxy() {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.nextcloud.talk.newarch.features.account.loginentry
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetCapabilitiesUseCase
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetProfileUseCase
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetSignalingSettingsUseCase
|
||||
|
||||
class LoginEntryViewModelFactory constructor(private val application: Application, private val getProfileUseCase: GetProfileUseCase, private val getCapabilitiesUseCase: GetCapabilitiesUseCase, private val getSignalingSettingsUseCase: GetSignalingSettingsUseCase, private val usersRepository: UsersRepository) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return LoginEntryViewModel(application, getProfileUseCase, getCapabilitiesUseCase, getSignalingSettingsUseCase, usersRepository) as T
|
||||
}
|
||||
}
|
@ -30,8 +30,11 @@ import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.lifecycle.Observer
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.newarch.conversationsList.mvp.BaseView
|
||||
import com.nextcloud.talk.newarch.features.account.loginentry.LoginEntryView
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||
import kotlinx.android.synthetic.main.server_entry_view.view.*
|
||||
import org.koin.android.ext.android.inject
|
||||
@ -54,7 +57,7 @@ class ServerEntryView : BaseView() {
|
||||
|
||||
viewModel.apply {
|
||||
checkState.observe(this@ServerEntryView, Observer {
|
||||
when(it.checkState) {
|
||||
when (it.checkState) {
|
||||
ServerEntryCapabilitiesCheckState.WAITING_FOR_INPUT -> {
|
||||
view.serverEntryTextInputLayout.isEnabled = true
|
||||
view.serverEntryProgressBar.isVisible = false
|
||||
@ -67,7 +70,8 @@ class ServerEntryView : BaseView() {
|
||||
ServerEntryCapabilitiesCheckState.SERVER_SUPPORTED -> {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(BundleKeys.KEY_BASE_URL, it.url)
|
||||
//router.pushController(RouterTransaction.with(LoginEntryView(bundle)).popChangeHandler(HorizontalChangeHandler()).pushChangeHandler(HorizontalChangeHandler()))
|
||||
router.pushController(RouterTransaction.with(LoginEntryView(bundle))
|
||||
.popChangeHandler(HorizontalChangeHandler()).pushChangeHandler(HorizontalChangeHandler()))
|
||||
}
|
||||
// Unsupported
|
||||
else -> {
|
||||
@ -96,8 +100,8 @@ class ServerEntryView : BaseView() {
|
||||
val drawableRight = 2
|
||||
val drawableBottom = 3
|
||||
|
||||
if(event.action == MotionEvent.ACTION_UP) {
|
||||
if(event.rawX >= (view.serverEntryTextInputEditText.right - view.serverEntryTextInputEditText.compoundDrawables[drawableRight].bounds.width())) {
|
||||
if (event.action == MotionEvent.ACTION_UP) {
|
||||
if (event.rawX >= (view.serverEntryTextInputEditText.right - view.serverEntryTextInputEditText.compoundDrawables[drawableRight].bounds.width())) {
|
||||
if (view.serverEntryTextInputEditText.compoundDrawables[drawableRight].alpha == 255) {
|
||||
view.serverEntryTextInputEditText?.text?.let { serverUrl ->
|
||||
var baseUrl = serverUrl.toString()
|
||||
|
@ -28,7 +28,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
|
||||
import com.nextcloud.talk.newarch.conversationsList.mvp.BaseViewModel
|
||||
import com.nextcloud.talk.newarch.data.model.ErrorModel
|
||||
import com.nextcloud.talk.newarch.domain.usecases.*
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetCapabilitiesUseCase
|
||||
import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
@ -53,11 +53,10 @@ class ServerEntryViewModel constructor(
|
||||
override suspend fun onError(errorModel: ErrorModel?) {
|
||||
if (url.startsWith("https://")) {
|
||||
fetchCapabilities(url.replace("https://", "http://"))
|
||||
} else {
|
||||
} else {
|
||||
checkState.postValue(ServerEntryCapabilitiesCheckStateWrapper(ServerEntryCapabilitiesCheckState.SERVER_UNSUPPORTED, url))
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.nextcloud.talk.newarch.domain.usecases.GetCapabilitiesUseCase
|
||||
|
||||
class ServerEntryViewModelFactory constructor(private val application: Application, private val getCapabilitiesUseCase: GetCapabilitiesUseCase): ViewModelProvider.Factory {
|
||||
class ServerEntryViewModelFactory constructor(private val application: Application, private val getCapabilitiesUseCase: GetCapabilitiesUseCase) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return ServerEntryViewModel(application, getCapabilitiesUseCase) as T
|
||||
}
|
||||
|
@ -121,8 +121,8 @@ open class ConversationsPresenter(context: Context, onElementClick: ((Page, Hold
|
||||
)
|
||||
} else {
|
||||
authorDisplayName = if (!TextUtils.isEmpty(conversation.lastMessage?.actorDisplayName)) {
|
||||
conversation.lastMessage?.actorDisplayName!!.substringBefore(" ") }
|
||||
else if ("guests" == conversation.lastMessage!!.actorType)
|
||||
conversation.lastMessage?.actorDisplayName!!.substringBefore(" ")
|
||||
} else if ("guests" == conversation.lastMessage!!.actorType)
|
||||
context.getString(R.string.nc_guest)
|
||||
else
|
||||
""
|
||||
|
@ -21,21 +21,23 @@
|
||||
package com.nextcloud.talk.newarch.local.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import com.bluelinelabs.logansquare.LoganSquare
|
||||
import com.nextcloud.talk.models.ExternalSignalingServer
|
||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettings
|
||||
import com.nextcloud.talk.newarch.utils.MagicJson
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class ExternalSignalingConverter {
|
||||
class SignalingSettingsConverter {
|
||||
val json = Json(MagicJson.customJsonConfiguration)
|
||||
@TypeConverter
|
||||
fun fromExternalSignalingToString(externalSignalingServer: ExternalSignalingServer?): String {
|
||||
if (externalSignalingServer == null) {
|
||||
return ""
|
||||
fun fromSignalingSettingsToString(signalingSettings: SignalingSettings?): String {
|
||||
return if (signalingSettings == null) {
|
||||
""
|
||||
} else {
|
||||
return LoganSquare.serialize(externalSignalingServer)
|
||||
json.stringify(SignalingSettings.serializer(), signalingSettings)
|
||||
}
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromStringToExternalSignaling(value: String): ExternalSignalingServer? {
|
||||
return LoganSquare.parse(value, ExternalSignalingServer::class.java)
|
||||
fun fromStringToSignalingSettings(value: String): SignalingSettings? {
|
||||
return json.parse(SignalingSettings.serializer(), value)
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@ import com.nextcloud.talk.newarch.local.models.UserNgEntity
|
||||
ConversationReadOnlyStateConverter::class, NotificationLevelConverter::class,
|
||||
ConversationTypeConverter::class, ParticipantTypeConverter::class,
|
||||
PushConfigurationConverter::class, CapabilitiesConverter::class,
|
||||
ExternalSignalingConverter::class,
|
||||
SignalingSettingsConverter::class,
|
||||
UserStatusConverter::class, SystemMessageTypeConverter::class, ParticipantMapConverter::class
|
||||
)
|
||||
|
||||
|
@ -24,9 +24,9 @@ import android.os.Parcelable
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.nextcloud.talk.models.ExternalSignalingServer
|
||||
import com.nextcloud.talk.models.json.capabilities.Capabilities
|
||||
import com.nextcloud.talk.models.json.push.PushConfigurationState
|
||||
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettings
|
||||
import com.nextcloud.talk.newarch.local.models.other.UserStatus
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
@ -47,8 +47,8 @@ data class UserNgEntity(
|
||||
@ColumnInfo(name = "capabilities") var capabilities: Capabilities? = null,
|
||||
@ColumnInfo(name = "client_auth_cert") var clientCertificate: String? = null,
|
||||
@ColumnInfo(
|
||||
name = "external_signaling"
|
||||
) var externalSignaling: ExternalSignalingServer? = null,
|
||||
name = "signaling_settings"
|
||||
) var signalingSettings: SignalingSettings? = null,
|
||||
@ColumnInfo(name = "status") var status: UserStatus? = null
|
||||
) : Parcelable {
|
||||
|
||||
@ -71,7 +71,7 @@ data class UserNgEntity(
|
||||
if (pushConfiguration != other.pushConfiguration) return false
|
||||
if (capabilities != other.capabilities) return false
|
||||
if (clientCertificate != other.clientCertificate) return false
|
||||
if (externalSignaling != other.externalSignaling) return false
|
||||
if (signalingSettings != other.signalingSettings) return false
|
||||
if (status != other.status) return false
|
||||
|
||||
return true
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
*
|
||||
* * Nextcloud Talk application
|
||||
* *
|
||||
* * @author Mario Danic
|
||||
* * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||
* *
|
||||
* * This program is free software: you can redistribute it and/or modify
|
||||
* * it under the terms of the GNU General Public License as published by
|
||||
* * the Free Software Foundation, either version 3 of the License, or
|
||||
* * at your option) any later version.
|
||||
* *
|
||||
* * This program is distributed in the hope that it will be useful,
|
||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* * GNU General Public License for more details.
|
||||
* *
|
||||
* * You should have received a copy of the GNU General Public License
|
||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.newarch.utils
|
||||
|
||||
import kotlinx.serialization.json.JsonConfiguration
|
||||
|
||||
sealed class MagicJson {
|
||||
companion object {
|
||||
private val defaultIndent: String = " "
|
||||
private val defaultDiscriminator = "type"
|
||||
|
||||
val customJsonConfiguration = JsonConfiguration(
|
||||
encodeDefaults = true,
|
||||
strictMode = true,
|
||||
unquoted = false,
|
||||
allowStructuredMapKeys = true,
|
||||
prettyPrint = true,
|
||||
indent = defaultIndent,
|
||||
useArrayPolymorphism = true,
|
||||
classDiscriminator = defaultDiscriminator
|
||||
)
|
||||
}
|
||||
}
|
24
app/src/main/res/layout/login_entry_view.xml
Normal file
24
app/src/main/res/layout/login_entry_view.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorPrimary">
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/stubImport"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:inflatedId="@+id/webViewImportLayout"
|
||||
android:layout="@layout/login_web_view" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="@dimen/item_height"
|
||||
android:layout_height="@dimen/item_height"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true"
|
||||
android:indeterminateTint="@color/white"
|
||||
android:indeterminateTintMode="src_in" />
|
||||
|
||||
</RelativeLayout>
|
41
app/src/main/res/layout/login_web_view.xml
Normal file
41
app/src/main/res/layout/login_web_view.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ /*
|
||||
~ * Nextcloud Talk application
|
||||
~ *
|
||||
~ * @author Mario Danic
|
||||
~ * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||
~ *
|
||||
~ * This program is free software: you can redistribute it and/or modify
|
||||
~ * it under the terms of the GNU General Public License as published by
|
||||
~ * the Free Software Foundation, either version 3 of the License, or
|
||||
~ * at your option) any later version.
|
||||
~ *
|
||||
~ * This program is distributed in the hope that it will be useful,
|
||||
~ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ * GNU General Public License for more details.
|
||||
~ *
|
||||
~ * You should have received a copy of the GNU General Public License
|
||||
~ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
~ */
|
||||
-->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pageProgressBar"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
android:background="@color/white"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<org.mozilla.geckoview.GeckoView
|
||||
android:id="@+id/geckoView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible"/>
|
||||
|
||||
</RelativeLayout>
|
10
build.gradle
10
build.gradle
@ -31,6 +31,9 @@ buildscript {
|
||||
maven {
|
||||
url 'https://jitpack.io'
|
||||
}
|
||||
maven {
|
||||
url 'https://maven.mozilla.org/maven2'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||
@ -54,10 +57,15 @@ allprojects {
|
||||
maven {
|
||||
url 'https://oss.sonatype.org/content/repositories/snapshots'
|
||||
}
|
||||
maven {
|
||||
url 'https://maven.mozilla.org/maven2'
|
||||
}
|
||||
maven {
|
||||
url 'https://jitpack.io'
|
||||
}
|
||||
maven { url 'https://maven.google.com' }
|
||||
maven {
|
||||
url 'https://maven.google.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user