diff --git a/app/build.gradle b/app/build.gradle index 3e9ff0fcb..bffbe663a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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 diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.kt b/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.kt index 53f6b121f..b4e4324a7 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.kt +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.kt @@ -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 diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt index a469df0bc..3f8a5c991 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt +++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt @@ -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)) } } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.kt b/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.kt index 689c11a3c..f3d0830b1 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.kt @@ -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) { diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt b/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt index dc7811944..c0f90f368 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt @@ -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 ) ) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.kt index 56a2c6c3b..51b36b83a 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/SignalingSettingsWorker.kt @@ -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 { diff --git a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/IceServer.java b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/IceServer.kt similarity index 50% rename from app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/IceServer.java rename to app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/IceServer.kt index 558a1dffb..4ba215fff 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/IceServer.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/IceServer.kt @@ -17,28 +17,30 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +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 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? = null, + @JvmField + @JsonField(name = ["username"]) + var username: String? = null, + @JvmField + @JsonField(name = ["credential"]) + var credential: String? = null +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/Settings.java b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/Settings.java deleted file mode 100644 index bf9b95e4e..000000000 --- a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/Settings.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017 Mario Danic - * - * 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 . - */ - -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 stunServers; - - @JsonField(name = "turnservers") - public List turnServers; - - @JsonField(name = "server") - public String externalSignalingServer; - - @JsonField(name = "ticket") - public String externalSignalingTicket; -} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettings.kt b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettings.kt new file mode 100644 index 000000000..142024da1 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettings.kt @@ -0,0 +1,46 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * + * 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 . + */ +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? = null, + @JvmField + @JsonField(name = ["turnservers"]) + var turnServers: List? = null, + @JvmField + @JsonField(name = ["server"]) + var externalSignalingServer: String? = null, + @JvmField + @JsonField(name = ["ticket"]) + var externalSignalingTicket: String? = null +) : Parcelable diff --git a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettingsOcs.java b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettingsOcs.java index 124e8f0b3..1c318395e 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettingsOcs.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/signaling/settings/SignalingSettingsOcs.java @@ -30,5 +30,5 @@ import lombok.Data; @JsonObject public class SignalingSettingsOcs extends GenericOCS { @JsonField(name = "data") - public Settings settings; + public SignalingSettings signalingSettings; } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/userprofile/UserProfileData.java b/app/src/main/java/com/nextcloud/talk/models/json/userprofile/UserProfileData.kt similarity index 64% rename from app/src/main/java/com/nextcloud/talk/models/json/userprofile/UserProfileData.java rename to app/src/main/java/com/nextcloud/talk/models/json/userprofile/UserProfileData.kt index 036a8c80c..26bf13759 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/userprofile/UserProfileData.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/userprofile/UserProfileData.kt @@ -18,25 +18,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -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 +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/data/repository/online/NextcloudTalkRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/newarch/data/repository/online/NextcloudTalkRepositoryImpl.kt index 013f69668..1d5d64e37 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/data/repository/online/NextcloudTalkRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/data/repository/online/NextcloudTalkRepositoryImpl.kt @@ -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): 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): Any { + return apiService.unregisterForPushWithProxy(ApiUtils.getUrlPushProxy(), options) + } + + override suspend fun unregisterPushWithProxyForUser(user: UserNgEntity, options: Map): 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 { return apiService.getConversations( user.getCredentials(), diff --git a/app/src/main/java/com/nextcloud/talk/newarch/data/source/remote/ApiService.kt b/app/src/main/java/com/nextcloud/talk/newarch/data/source/remote/ApiService.kt index fc35dcb13..eda04c26a 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/data/source/remote/ApiService.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/data/source/remote/ApiService.kt @@ -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): PushRegistrationOverall + + @DELETE + fun unregisterForPushWithServer(@Header("Authorization") authorization: String, + @Url url: String): GenericOverall + + @FormUrlEncoded + @POST + fun registerForPushWithProxy(@Url url: String, + @FieldMap fields: Map): Any + + /* + QueryMap items are as follows: + - "deviceIdentifier": "{{deviceIdentifier}}", + - "deviceIdentifierSignature": "{{signature}}", + - "userPublicKey": "{{userPublicKey}}" + */ + @DELETE + fun unregisterForPushWithProxy(@Url url: String?, + @QueryMap fields: Map): Any + @GET suspend fun getConversations( @Header( diff --git a/app/src/main/java/com/nextcloud/talk/newarch/di/module/ConversationsModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/di/module/ConversationsModule.kt deleted file mode 100644 index dcd2ddaa7..000000000 --- a/app/src/main/java/com/nextcloud/talk/newarch/di/module/ConversationsModule.kt +++ /dev/null @@ -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) -} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/di/module/ServerModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/di/module/ServerModule.kt index 4ff155c04..f87dc1f0a 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/di/module/ServerModule.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/di/module/ServerModule.kt @@ -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) } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/online/NextcloudTalkRepository.kt b/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/online/NextcloudTalkRepository.kt index e5f52c6ef..d053f6ae3 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/online/NextcloudTalkRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/online/NextcloudTalkRepository.kt @@ -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): PushRegistrationOverall + suspend fun unregisterPushWithServerForUser(user: UserNgEntity): GenericOverall + suspend fun registerPushWithProxyForUser(user: UserNgEntity, options: Map): Any + suspend fun unregisterPushWithProxyForUser(user: UserNgEntity, options: Map): Any + + suspend fun getSignalingSettingsForUser(user: UserNgEntity): SignalingSettingsOverall + suspend fun getProfileForUser(user: UserNgEntity): UserProfileOverall suspend fun getConversationsForUser(user: UserNgEntity): List suspend fun setFavoriteValueForConversation( user: UserNgEntity, diff --git a/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetProfileUseCase.kt b/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetProfileUseCase.kt new file mode 100644 index 000000000..7151262a0 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetProfileUseCase.kt @@ -0,0 +1,39 @@ +/* + * + * * Nextcloud Talk application + * * + * * @author Mario Danic + * * Copyright (C) 2017-2020 Mario Danic + * * + * * 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 . + * + */ + +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(apiErrorHandler) { + override suspend fun run(params: Any?): UserProfileOverall { + val definitionParameters = params as DefinitionParameters + return nextcloudTalkRepository.getProfileForUser(definitionParameters[0]) + } +} diff --git a/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetSignalingSettingsUseCase.kt b/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetSignalingSettingsUseCase.kt new file mode 100644 index 000000000..aac7ac2fd --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetSignalingSettingsUseCase.kt @@ -0,0 +1,39 @@ +/* + * + * * Nextcloud Talk application + * * + * * @author Mario Danic + * * Copyright (C) 2017-2020 Mario Danic + * * + * * 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 . + * + */ + +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(apiErrorHandler) { + override suspend fun run(params: Any?): SignalingSettingsOverall { + val definitionParameters = params as DefinitionParameters + return nextcloudTalkRepository.getSignalingSettingsForUser(definitionParameters[0]) + } +} diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/account/di/module/AccountModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/account/di/module/AccountModule.kt index 8770a1b7b..1fc8413fb 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/account/di/module/AccountModule.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/account/di/module/AccountModule.kt @@ -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 + ) } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryState.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryState.kt new file mode 100644 index 000000000..5e5c65250 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryState.kt @@ -0,0 +1,47 @@ +/* + * + * * Nextcloud Talk application + * * + * * @author Mario Danic + * * Copyright (C) 2017-2020 Mario Danic + * * + * * 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 . + * + */ + +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?) \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryView.kt new file mode 100644 index 000000000..443e60cd8 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryView.kt @@ -0,0 +1,143 @@ +/* + * + * * Nextcloud Talk application + * * + * * @author Mario Danic + * * Copyright (C) 2017-2020 Mario Danic + * * + * * 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 . + * + */ + +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("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? { + 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 + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryViewModel.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryViewModel.kt new file mode 100644 index 000000000..439bf5c21 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryViewModel.kt @@ -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(application) { + val state: MutableLiveData = 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 { + 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 { + 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 { + 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() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryViewModelFactory.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryViewModelFactory.kt new file mode 100644 index 000000000..be2e8767f --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/account/loginentry/LoginEntryViewModelFactory.kt @@ -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 create(modelClass: Class): T { + return LoginEntryViewModel(application, getProfileUseCase, getCapabilitiesUseCase, getSignalingSettingsUseCase, usersRepository) as T + } +} diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryView.kt index 549d5b565..4cf59cc9e 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryView.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryView.kt @@ -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() diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryViewModel.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryViewModel.kt index 88299445a..554d6b416 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryViewModel.kt @@ -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)) } } - }) } } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryViewModelFactory.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryViewModelFactory.kt index adbb31bfb..c1c339d9b 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryViewModelFactory.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/account/serverentry/ServerEntryViewModelFactory.kt @@ -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 create(modelClass: Class): T { return ServerEntryViewModel(application, getCapabilitiesUseCase) as T } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt index c36c7fe90..b93102cec 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationPresenter.kt @@ -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 "" diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/converters/ExternalSignalingConverter.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/converters/SignalingSettingsConverter.kt similarity index 60% rename from app/src/main/java/com/nextcloud/talk/newarch/local/converters/ExternalSignalingConverter.kt rename to app/src/main/java/com/nextcloud/talk/newarch/local/converters/SignalingSettingsConverter.kt index 90118f2f8..c96cce655 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/local/converters/ExternalSignalingConverter.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/local/converters/SignalingSettingsConverter.kt @@ -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) } } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/db/TalkDatabase.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/db/TalkDatabase.kt index d8772f2a5..74fbecc5c 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/local/db/TalkDatabase.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/local/db/TalkDatabase.kt @@ -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 ) diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/models/UserNgEntity.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/models/UserNgEntity.kt index 7e0298b59..7b116d478 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/local/models/UserNgEntity.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/local/models/UserNgEntity.kt @@ -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 diff --git a/app/src/main/java/com/nextcloud/talk/newarch/utils/MagicJson.kt b/app/src/main/java/com/nextcloud/talk/newarch/utils/MagicJson.kt new file mode 100644 index 000000000..c2f29bf9a --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/newarch/utils/MagicJson.kt @@ -0,0 +1,43 @@ +/* + * + * * Nextcloud Talk application + * * + * * @author Mario Danic + * * Copyright (C) 2017-2020 Mario Danic + * * + * * 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 . + * + */ + +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 + ) + } +} diff --git a/app/src/main/res/layout/login_entry_view.xml b/app/src/main/res/layout/login_entry_view.xml new file mode 100644 index 000000000..5329ae43c --- /dev/null +++ b/app/src/main/res/layout/login_entry_view.xml @@ -0,0 +1,24 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/login_web_view.xml b/app/src/main/res/layout/login_web_view.xml new file mode 100644 index 000000000..f52a502a1 --- /dev/null +++ b/app/src/main/res/layout/login_web_view.xml @@ -0,0 +1,41 @@ + + + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 6fc4dedfd..b082e6e88 100644 --- a/build.gradle +++ b/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' + } } }