Further progress on user migration

This commit is contained in:
Mario Danic 2019-12-08 15:15:22 +01:00
parent b492c8a576
commit a695a8448d
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
26 changed files with 611 additions and 612 deletions

View File

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "c7b1b47572d7ace1b422d0a3887a54e1",
"identityHash": "3cabfd9fea2cd5a25c6c1c8103ef65fb",
"entities": [
{
"tableName": "conversations",
@ -287,13 +287,13 @@
},
{
"tableName": "users",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `user_id` TEXT NOT NULL, `username` TEXT NOT NULL, `base_url` TEXT NOT NULL, `token` TEXT, `display_name` TEXT, `push_configuration` TEXT, `capabilities` TEXT, `client_auth_cert` TEXT, `external_signaling` TEXT, `status` INTEGER)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `user_id` TEXT NOT NULL, `username` TEXT NOT NULL, `base_url` TEXT NOT NULL, `token` TEXT, `display_name` TEXT, `push_configuration` TEXT, `capabilities` TEXT, `client_auth_cert` TEXT, `external_signaling` TEXT, `status` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
"notNull": false
},
{
"fieldPath": "userId",
@ -369,7 +369,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c7b1b47572d7ace1b422d0a3887a54e1')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3cabfd9fea2cd5a25c6c1c8103ef65fb')"
]
}
}

View File

@ -42,6 +42,7 @@ import com.nextcloud.talk.controllers.CallNotificationController
import com.nextcloud.talk.controllers.LockedController
import com.nextcloud.talk.controllers.ServerSelectionController
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
import com.nextcloud.talk.newarch.features.conversationsList.ConversationsListView
import com.nextcloud.talk.utils.ConductorRemapping
import com.nextcloud.talk.utils.SecurityUtils
@ -50,6 +51,9 @@ import com.nextcloud.talk.utils.database.user.UserUtils
import io.requery.Persistable
import io.requery.android.sqlcipher.SqlCipherDatabaseSource
import io.requery.reactivex.ReactiveEntityStore
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
@ -60,10 +64,8 @@ class MainActivity : BaseActivity(), ActionBarProvider {
@BindView(R.id.controller_container)
lateinit var container: ViewGroup
@Inject
lateinit var userUtils: UserUtils
@Inject
lateinit var dataStore: ReactiveEntityStore<Persistable>
val usersRepository: UsersRepository by inject()
@Inject
lateinit var sqlCipherDatabaseSource: SqlCipherDatabaseSource
@ -89,6 +91,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
hasDb = false
}
if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
if (!router!!.hasRootController()) {
router!!.setRoot(
@ -100,18 +103,26 @@ class MainActivity : BaseActivity(), ActionBarProvider {
onNewIntent(intent)
} else if (!router!!.hasRootController()) {
if (hasDb) {
if (userUtils.anyUserExists()) {
router!!.setRoot(
RouterTransaction.with(ConversationsListView())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} else {
router!!.setRoot(
RouterTransaction.with(ServerSelectionController())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
GlobalScope.launch {
if (usersRepository.getUsers().count() > 0) {
runOnUiThread {
router!!.setRoot(
RouterTransaction.with(ConversationsListView())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
}
} else {
runOnUiThread {
router!!.setRoot(
RouterTransaction.with(ServerSelectionController())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
}
}
}
} else {
router!!.setRoot(

View File

@ -1,497 +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.controllers;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import autodagger.AutoInjector;
import butterknife.BindView;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.events.EventStatus;
import com.nextcloud.talk.jobs.CapabilitiesWorker;
import com.nextcloud.talk.jobs.PushRegistrationWorker;
import com.nextcloud.talk.jobs.SignalingSettingsWorker;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.conversations.RoomsOverall;
import com.nextcloud.talk.models.json.generic.Status;
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall;
import com.nextcloud.talk.newarch.features.conversationsList.ConversationsListView;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.ClosedInterfaceImpl;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
import com.uber.autodispose.AutoDispose;
import io.reactivex.CompletableObserver;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import java.net.CookieManager;
import javax.inject.Inject;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@AutoInjector(NextcloudTalkApplication.class)
public class AccountVerificationController extends BaseController {
public static final String TAG = "AccountVerificationController";
@Inject
NcApi ncApi;
@Inject
UserUtils userUtils;
@Inject
CookieManager cookieManager;
@Inject
AppPreferences appPreferences;
@Inject
EventBus eventBus;
@BindView(R.id.progress_text)
TextView progressText;
private long internalAccountId = -1;
private String baseUrl;
private String username;
private String token;
private boolean isAccountImport;
private String originalProtocol;
public AccountVerificationController(Bundle args) {
super();
if (args != null) {
baseUrl = args.getString(BundleKeys.INSTANCE.getKEY_BASE_URL());
username = args.getString(BundleKeys.INSTANCE.getKEY_USERNAME());
token = args.getString(BundleKeys.INSTANCE.getKEY_TOKEN());
if (args.containsKey(BundleKeys.INSTANCE.getKEY_IS_ACCOUNT_IMPORT())) {
isAccountImport = true;
}
if (args.containsKey(BundleKeys.INSTANCE.getKEY_ORIGINAL_PROTOCOL())) {
originalProtocol = args.getString(BundleKeys.INSTANCE.getKEY_ORIGINAL_PROTOCOL());
}
}
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_account_verification, container, false);
}
@Override
protected void onDetach(@NonNull View view) {
eventBus.unregister(this);
super.onDetach(view);
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
eventBus.register(this);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.Companion.getSharedApplication()
.getComponentApplication()
.inject(this);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
if (getActionBar() != null) {
getActionBar().hide();
}
if (isAccountImport && !baseUrl.startsWith("http://") && !baseUrl.startsWith("https://")
|| (!TextUtils
.isEmpty(originalProtocol) && !baseUrl.startsWith(originalProtocol))) {
determineBaseUrlProtocol(true);
} else {
checkEverything();
}
}
private void checkEverything() {
String credentials = ApiUtils.getCredentials(username, token);
cookieManager.getCookieStore().removeAll();
findServerTalkApp(credentials);
}
private void determineBaseUrlProtocol(boolean checkForcedHttps) {
cookieManager.getCookieStore().removeAll();
String queryUrl;
baseUrl = baseUrl.replace("http://", "").replace("https://", "");
if (checkForcedHttps) {
queryUrl = "https://" + baseUrl + ApiUtils.getUrlPostfixForStatus();
} else {
queryUrl = "http://" + baseUrl + ApiUtils.getUrlPostfixForStatus();
}
ncApi.getServerStatus(queryUrl)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<Status>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Status status) {
if (checkForcedHttps) {
baseUrl = "https://" + baseUrl;
} else {
baseUrl = "http://" + baseUrl;
}
if (isAccountImport) {
getRouter().replaceTopController(
RouterTransaction.with(new WebViewLoginController(baseUrl,
false, username, ""))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
checkEverything();
}
}
@Override
public void onError(Throwable e) {
if (checkForcedHttps) {
determineBaseUrlProtocol(false);
} else {
abortVerification();
}
}
@Override
public void onComplete() {
}
});
}
private void findServerTalkApp(String credentials) {
ncApi.getRooms(credentials, ApiUtils.getUrlForGetRooms(baseUrl))
.subscribeOn(Schedulers.io())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<RoomsOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(RoomsOverall roomsOverall) {
fetchProfile(credentials);
}
@Override
public void onError(Throwable e) {
if (getActivity() != null && getResources() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(String.format(getResources().getString(
R.string.nc_nextcloud_talk_app_not_installed),
getResources().getString(R.string.nc_app_name))));
}
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK);
abortVerification();
}
@Override
public void onComplete() {
}
});
}
private void storeProfile(String displayName, String userId) {
userUtils.createOrUpdateUser(username, token,
baseUrl, displayName, null, true,
userId, null, null,
appPreferences.getTemporaryClientCertAlias(), null)
.subscribeOn(Schedulers.io())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<UserEntity>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(UserEntity userEntity) {
internalAccountId = userEntity.getId();
if (new ClosedInterfaceImpl().isGooglePlayServicesAvailable()) {
registerForPush();
} else {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_push_disabled)));
fetchAndStoreCapabilities();
}
}
@Override
public void onError(Throwable e) {
progressText.setText(progressText.getText().toString() +
"\n" +
getResources().getString(
R.string.nc_display_name_not_stored));
abortVerification();
}
@Override
public void onComplete() {
}
});
}
private void fetchProfile(String credentials) {
ncApi.getUserProfile(credentials,
ApiUtils.getUrlForUserProfile(baseUrl))
.subscribeOn(Schedulers.io())
.as(AutoDispose.autoDisposable(getScopeProvider()))
.subscribe(new Observer<UserProfileOverall>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(UserProfileOverall userProfileOverall) {
String displayName = 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;
}
if (!TextUtils.isEmpty(displayName)) {
storeProfile(displayName, userProfileOverall.ocs.data.userId);
} else {
if (getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_display_name_not_fetched)));
}
abortVerification();
}
}
@Override
public void onError(Throwable e) {
if (getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_display_name_not_fetched)));
}
abortVerification();
}
@Override
public void onComplete() {
}
});
}
private void registerForPush() {
OneTimeWorkRequest pushRegistrationWork =
new OneTimeWorkRequest.Builder(PushRegistrationWorker.class).build();
WorkManager.getInstance().enqueue(pushRegistrationWork);
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEvent(EventStatus eventStatus) {
if (EventStatus.EventType.PUSH_REGISTRATION == eventStatus.eventType) {
if (internalAccountId == eventStatus.userId
&& !eventStatus.allGood
&& getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_push_disabled)));
}
fetchAndStoreCapabilities();
} else if (EventStatus.EventType.CAPABILITIES_FETCH == eventStatus.eventType) {
if (internalAccountId == eventStatus.userId && !eventStatus.allGood) {
if (getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_capabilities_failed)));
}
abortVerification();
} else if (internalAccountId == eventStatus.userId && eventStatus.allGood) {
fetchAndStoreExternalSignalingSettings();
}
} else if (EventStatus.EventType.SIGNALING_SETTINGS == eventStatus.eventType) {
if (internalAccountId == eventStatus.userId && !eventStatus.allGood) {
if (getActivity() != null) {
getActivity().runOnUiThread(
() -> progressText.setText(progressText.getText().toString() + "\n" +
getResources().getString(R.string.nc_external_server_failed)));
}
}
proceedWithLogin();
}
}
private void fetchAndStoreCapabilities() {
Data userData = new Data.Builder()
.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), internalAccountId)
.build();
OneTimeWorkRequest pushNotificationWork =
new OneTimeWorkRequest.Builder(CapabilitiesWorker.class)
.setInputData(userData)
.build();
WorkManager.getInstance().enqueue(pushNotificationWork);
}
private void fetchAndStoreExternalSignalingSettings() {
Data userData = new Data.Builder()
.putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), internalAccountId)
.build();
OneTimeWorkRequest signalingSettings =
new OneTimeWorkRequest.Builder(SignalingSettingsWorker.class)
.setInputData(userData)
.build();
WorkManager.getInstance().enqueue(signalingSettings);
}
private void proceedWithLogin() {
cookieManager.getCookieStore().removeAll();
userUtils.disableAllUsersWithoutId(internalAccountId);
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
if (userUtils.getUsers().size() == 1) {
getRouter().setRoot(RouterTransaction.with(new
ConversationsListView())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
if (isAccountImport) {
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.ACCOUNT_WAS_IMPORTED);
}
getRouter().popToRoot();
}
});
}
}
@Override
protected void onDestroyView(@NonNull View view) {
super.onDestroyView(view);
if (getActivity() != null) {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
}
}
private void abortVerification() {
if (!isAccountImport) {
if (internalAccountId != -1) {
userUtils.deleteUserWithId(internalAccountId).subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
new Handler().postDelayed(() -> getRouter().popToRoot(), 7500);
});
}
}
@Override
public void onError(Throwable e) {
}
});
} else {
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
new Handler().postDelayed(() -> getRouter().popToRoot(), 7500);
});
}
}
} else {
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT);
if (getActivity() != null) {
getActivity().runOnUiThread(() -> new Handler().postDelayed(() -> {
if (getRouter().hasRootController()) {
if (getActivity() != null) {
getRouter().popToRoot();
}
} else {
if (userUtils.anyUserExists()) {
getRouter().setRoot(RouterTransaction.with(new ConversationsListView())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
} else {
getRouter().setRoot(RouterTransaction.with(new ServerSelectionController())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler()));
}
}
}, 7500));
}
}
}
}

View File

@ -0,0 +1,453 @@
/*
* 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.controllers
import android.content.pm.ActivityInfo
import android.os.Bundle
import android.os.Handler
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.work.Data
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import autodagger.AutoInjector
import butterknife.BindView
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
import com.nextcloud.talk.R
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.controllers.base.BaseController
import com.nextcloud.talk.events.EventStatus
import com.nextcloud.talk.jobs.CapabilitiesWorker
import com.nextcloud.talk.jobs.PushRegistrationWorker
import com.nextcloud.talk.jobs.SignalingSettingsWorker
import com.nextcloud.talk.models.json.conversations.RoomsOverall
import com.nextcloud.talk.models.json.generic.Status
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
import com.nextcloud.talk.newarch.features.conversationsList.ConversationsListView
import com.nextcloud.talk.newarch.local.dao.UsersDao
import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.ClosedInterfaceImpl
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
import com.uber.autodispose.AutoDispose
import com.uber.autodispose.ObservableSubscribeProxy
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.koin.core.KoinComponent
import org.koin.core.inject
import java.net.CookieManager
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
class AccountVerificationController(args: Bundle?) : BaseController(), KoinComponent {
@JvmField @Inject
internal var ncApi: NcApi? = null
val cookieManager: CookieManager by inject()
val usersRepository: UsersRepository by inject()
val usersDao: UsersDao by inject()
@JvmField @BindView(R.id.progress_text)
internal var progressText: TextView? = null
private var internalAccountId: Long = -1
private var baseUrl: String? = null
private var username: String? = null
private var token: String? = null
private var isAccountImport: Boolean = false
private var originalProtocol: String? = null
init {
if (args != null) {
baseUrl = args.getString(BundleKeys.KEY_BASE_URL)
username = args.getString(BundleKeys.KEY_USERNAME)
token = args.getString(BundleKeys.KEY_TOKEN)
if (args.containsKey(BundleKeys.KEY_IS_ACCOUNT_IMPORT)) {
isAccountImport = true
}
if (args.containsKey(BundleKeys.KEY_ORIGINAL_PROTOCOL)) {
originalProtocol = args.getString(BundleKeys.KEY_ORIGINAL_PROTOCOL)
}
}
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
return inflater.inflate(R.layout.controller_account_verification, container, false)
}
override fun onDetach(view: View) {
eventBus.unregister(this)
super.onDetach(view)
}
override fun onAttach(view: View) {
super.onAttach(view)
eventBus.register(this)
}
override fun onViewBound(view: View) {
super.onViewBound(view)
NextcloudTalkApplication.sharedApplication!!
.componentApplication
.inject(this)
if (activity != null) {
activity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
if (actionBar != null) {
actionBar!!.hide()
}
if (isAccountImport && !baseUrl!!.startsWith("http://") && !baseUrl!!.startsWith("https://") || !TextUtils
.isEmpty(originalProtocol) && !baseUrl!!.startsWith(originalProtocol!!)) {
determineBaseUrlProtocol(true)
} else {
checkEverything()
}
}
private fun checkEverything() {
val credentials = ApiUtils.getCredentials(username, token)
cookieManager.cookieStore.removeAll()
findServerTalkApp(credentials)
}
private fun determineBaseUrlProtocol(checkForcedHttps: Boolean) {
cookieManager.cookieStore.removeAll()
val queryUrl: String
baseUrl = baseUrl!!.replace("http://", "").replace("https://", "")
if (checkForcedHttps) {
queryUrl = "https://" + baseUrl + ApiUtils.getUrlPostfixForStatus()
} else {
queryUrl = "http://" + baseUrl + ApiUtils.getUrlPostfixForStatus()
}
ncApi!!.getServerStatus(queryUrl)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.`as`<ObservableSubscribeProxy<Status>>(AutoDispose.autoDisposable(scopeProvider))
.subscribe(object : Observer<Status> {
override fun onSubscribe(d: Disposable) {}
override fun onNext(status: Status) {
if (checkForcedHttps) {
baseUrl = "https://" + baseUrl!!
} else {
baseUrl = "http://" + baseUrl!!
}
if (isAccountImport) {
router.replaceTopController(
RouterTransaction.with(WebViewLoginController(baseUrl,
false, username, ""))
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
} else {
checkEverything()
}
}
override fun onError(e: Throwable) {
if (checkForcedHttps) {
determineBaseUrlProtocol(false)
} else {
GlobalScope.launch {
abortVerification()
}
}
}
override fun onComplete() {
}
})
}
private fun findServerTalkApp(credentials: String?) {
ncApi!!.getRooms(credentials, ApiUtils.getUrlForGetRooms(baseUrl))
.subscribeOn(Schedulers.io())
.`as`<ObservableSubscribeProxy<RoomsOverall>>(AutoDispose.autoDisposable(scopeProvider))
.subscribe(object : Observer<RoomsOverall> {
override fun onSubscribe(d: Disposable) {}
override fun onNext(roomsOverall: RoomsOverall) {
fetchProfile(credentials)
}
override fun onError(e: Throwable) {
if (activity != null && resources != null) {
activity!!.runOnUiThread {
progressText!!.text = String.format(resources!!.getString(
R.string.nc_nextcloud_talk_app_not_installed),
resources!!.getString(R.string.nc_app_name))
}
}
ApplicationWideMessageHolder.getInstance().setMessageType(
ApplicationWideMessageHolder.MessageType.SERVER_WITHOUT_TALK)
GlobalScope.launch {
abortVerification()
}
}
override fun onComplete() {
}
})
}
private suspend fun storeProfile(displayName: String?, userId: String) {
var user = usersRepository.getUserWithUsernameAndServer(username!!, baseUrl!!)
if (user == null) {
user = UserNgEntity(null, userId, username!!, baseUrl!!, token, displayName)
internalAccountId = usersDao.saveUser(user)
} else {
user.displayName = displayName
usersRepository.updateUser(user)
internalAccountId = user.id!!
}
if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) {
registerForPush()
} else {
activity!!.runOnUiThread {
progressText!!.text = progressText!!.text.toString() + "\n" +
resources!!.getString(R.string.nc_push_disabled)
}
fetchAndStoreCapabilities()
}
}
private fun fetchProfile(credentials: String?) {
ncApi!!.getUserProfile(credentials,
ApiUtils.getUrlForUserProfile(baseUrl))
.subscribeOn(Schedulers.io())
.`as`<ObservableSubscribeProxy<UserProfileOverall>>(AutoDispose.autoDisposable(scopeProvider))
.subscribe(object : Observer<UserProfileOverall> {
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
}
if (!TextUtils.isEmpty(displayName)) {
GlobalScope.launch {
storeProfile(displayName, userProfileOverall.ocs.data.userId)
}
} else {
if (activity != null) {
activity!!.runOnUiThread {
progressText!!.text = progressText!!.text.toString() + "\n" +
resources!!.getString(R.string.nc_display_name_not_fetched)
}
}
GlobalScope.launch {
abortVerification()
}
}
}
override fun onError(e: Throwable) {
if (activity != null) {
activity!!.runOnUiThread {
progressText!!.text = progressText!!.text.toString() + "\n" +
resources!!.getString(R.string.nc_display_name_not_fetched)
}
}
GlobalScope.launch {
abortVerification()
}
}
override fun onComplete() {
}
})
}
private fun registerForPush() {
val pushRegistrationWork = OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java).build()
WorkManager.getInstance().enqueue(pushRegistrationWork)
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
fun onMessageEvent(eventStatus: EventStatus) {
if (EventStatus.EventType.PUSH_REGISTRATION == eventStatus.eventType) {
if (internalAccountId == eventStatus.userId
&& !eventStatus.allGood
&& activity != null) {
activity!!.runOnUiThread {
progressText!!.text = progressText!!.text.toString() + "\n" +
resources!!.getString(R.string.nc_push_disabled)
}
}
fetchAndStoreCapabilities()
} else if (EventStatus.EventType.CAPABILITIES_FETCH == eventStatus.eventType) {
if (internalAccountId == eventStatus.userId && !eventStatus.allGood) {
if (activity != null) {
activity!!.runOnUiThread {
progressText!!.text = progressText!!.text.toString() + "\n" +
resources!!.getString(R.string.nc_capabilities_failed)
}
}
GlobalScope.launch {
abortVerification()
}
} else if (internalAccountId == eventStatus.userId && eventStatus.allGood) {
fetchAndStoreExternalSignalingSettings()
}
} else if (EventStatus.EventType.SIGNALING_SETTINGS == eventStatus.eventType) {
if (internalAccountId == eventStatus.userId && !eventStatus.allGood) {
if (activity != null) {
activity!!.runOnUiThread {
progressText!!.text = progressText!!.text.toString() + "\n" +
resources!!.getString(R.string.nc_external_server_failed)
}
}
}
GlobalScope.launch {
proceedWithLogin()
}
}
}
private fun fetchAndStoreCapabilities() {
val userData = Data.Builder()
.putLong(BundleKeys.KEY_INTERNAL_USER_ID, internalAccountId)
.build()
val pushNotificationWork = OneTimeWorkRequest.Builder(CapabilitiesWorker::class.java)
.setInputData(userData)
.build()
WorkManager.getInstance().enqueue(pushNotificationWork)
}
private fun fetchAndStoreExternalSignalingSettings() {
val userData = Data.Builder()
.putLong(BundleKeys.KEY_INTERNAL_USER_ID, internalAccountId)
.build()
val signalingSettings = OneTimeWorkRequest.Builder(SignalingSettingsWorker::class.java)
.setInputData(userData)
.build()
WorkManager.getInstance().enqueue(signalingSettings)
}
private suspend fun proceedWithLogin() {
cookieManager.cookieStore.removeAll()
usersRepository.setUserAsActiveWithId(internalAccountId)
if (activity != null) {
if (usersRepository.getUsers().count() == 1) {
activity!!.runOnUiThread {
router.setRoot(RouterTransaction.with(ConversationsListView())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
}
} else {
if (isAccountImport) {
ApplicationWideMessageHolder.getInstance().messageType = ApplicationWideMessageHolder.MessageType.ACCOUNT_WAS_IMPORTED
}
activity!!.runOnUiThread {
router.popToRoot()
}
}
}
}
override fun onDestroyView(view: View) {
super.onDestroyView(view)
if (activity != null) {
activity!!.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
}
}
private suspend fun abortVerification() {
if (!isAccountImport) {
if (internalAccountId != -1L) {
usersRepository.deleteUserWithId(internalAccountId)
activity!!.runOnUiThread { Handler().postDelayed({ router.popToRoot() }, 7500) }
} else {
if (activity != null) {
activity!!.runOnUiThread { Handler().postDelayed({ router.popToRoot() }, 7500) }
}
}
} else {
ApplicationWideMessageHolder.getInstance().messageType =
ApplicationWideMessageHolder.MessageType.FAILED_TO_IMPORT_ACCOUNT
if (activity != null) {
activity!!.runOnUiThread {
Handler().postDelayed({
if (router.hasRootController()) {
if (activity != null) {
router.popToRoot()
}
} else {
if (usersRepository.getUsers().count() > 0) {
router.setRoot(RouterTransaction.with(ConversationsListView())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
} else {
router.setRoot(RouterTransaction.with(ServerSelectionController())
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler()))
}
}
}, 7500)
}
}
}
}
companion object {
const val TAG = "AccountVerificationController"
}
}

View File

@ -1017,11 +1017,11 @@ class ChatController(args: Bundle) : BaseController(), MessagesListAdapter
private fun setupWebsocket() {
if (conversationUser != null) {
if (WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(
conversationUser.id
conversationUser.id!!
) != null
) {
magicWebSocketInstance =
WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(conversationUser.id)
WebSocketConnectionHelper.getMagicWebSocketInstanceForUserId(conversationUser.id!!)
} else {
magicWebSocketInstance = null
}
@ -1489,7 +1489,7 @@ class ChatController(args: Bundle) : BaseController(), MessagesListAdapter
null && roomOverall.ocs.data.token != null
) {
ConductorRemapping.remapChatController(
router, conversationUser.id,
router, conversationUser.id!!,
roomOverall.ocs.data.token!!, bundle, false
)
}

View File

@ -332,7 +332,7 @@ class ContactsController : BaseController,
ConductorRemapping.remapChatController(
router,
currentUser!!.id,
currentUser!!.id!!,
roomOverall.ocs.data.token!!, bundle, true
)
}
@ -389,7 +389,7 @@ class ContactsController : BaseController,
val groupIdsArray = selectedGroupIds.toTypedArray()
val data = Data.Builder()
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, currentUser!!.id)
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, currentUser!!.id!!)
data.putString(BundleKeys.KEY_TOKEN, conversationToken)
data.putStringArray(BundleKeys.KEY_SELECTED_USERS, userIdsArray)
data.putStringArray(BundleKeys.KEY_SELECTED_GROUPS, groupIdsArray)
@ -893,7 +893,7 @@ class ContactsController : BaseController,
ConductorRemapping.remapChatController(
router,
currentUser!!.id,
currentUser!!.id!!,
roomOverall.ocs.data.token!!, bundle, true
)
} else {

View File

@ -192,7 +192,7 @@ class ConversationInfoController(args: Bundle) : BaseController(),
if (!TextUtils.isEmpty(conversationToken) && conversationUser != null) {
val data = Data.Builder()
data.putString(BundleKeys.KEY_ROOM_TOKEN, conversationToken)
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id)
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id!!)
return data.build()
}

View File

@ -74,7 +74,7 @@ class AddParticipantsToConversation(context: Context,
.subscribeOn(Schedulers.io())
.blockingSubscribe()
}
eventBus.post(EventStatus(user.id, EventStatus.EventType.PARTICIPANTS_UPDATE, true))
eventBus.post(EventStatus(user.id!!, EventStatus.EventType.PARTICIPANTS_UPDATE, true))
return Result.success()
}

View File

@ -55,7 +55,7 @@ class CapabilitiesWorker(context: Context, workerParams: WorkerParameters) : Cor
internalUserEntity.capabilities = capabilitiesOverall.ocs.data.capabilities
runBlocking {
val result = usersRepository.updateUser(internalUserEntity)
eventBus!!.post(EventStatus(internalUserEntity.id,
eventBus!!.post(EventStatus(internalUserEntity.id!!,
EventStatus.EventType.CAPABILITIES_FETCH, result > 0))
}
@ -87,7 +87,7 @@ class CapabilitiesWorker(context: Context, workerParams: WorkerParameters) : Cor
}
override fun onError(e: Throwable) {
eventBus.post(EventStatus(internalUserEntity.id,
eventBus.post(EventStatus(internalUserEntity.id!!,
EventStatus.EventType.CAPABILITIES_FETCH, false))
}

View File

@ -59,7 +59,7 @@ class LeaveConversationWorker(context: Context, workerParams: WorkerParameters)
if (operationUser != null) {
val credentials = operationUser.getCredentials()
ncApi = retrofit.newBuilder().client(okHttpClient.newBuilder().cookieJar(JavaNetCookieJar(CookieManager())).build()).build().create(NcApi::class.java)
val eventStatus = EventStatus(operationUser.id,
val eventStatus = EventStatus(operationUser.id!!,
EventStatus.EventType.CONVERSATION_UPDATE, true)
ncApi!!.removeSelfFromRoom(credentials,
ApiUtils.getUrlForRemoveSelfFromRoom(operationUser.baseUrl, conversationToken))

View File

@ -154,7 +154,7 @@ class NotificationWorker(
var arbitraryStorageEntity: ArbitraryStorageEntity?
arbitraryStorageEntity = arbitraryStorageUtils!!.getStorageSetting(
userEntity.id,
userEntity.id!!,
"mute_calls",
intent.extras!!.getString(KEY_ROOM_TOKEN)
)
@ -164,7 +164,7 @@ class NotificationWorker(
}
arbitraryStorageEntity = arbitraryStorageUtils!!.getStorageSetting(
userEntity.id,
userEntity.id!!,
"important_conversation",
intent.extras!!.getString(KEY_ROOM_TOKEN)
)
@ -366,7 +366,7 @@ class NotificationWorker(
val notificationInfo = Bundle()
notificationInfo.putLong(
KEY_INTERNAL_USER_ID,
signatureVerification!!.userEntity.id
signatureVerification!!.userEntity.id!!
)
// could be an ID or a TOKEN

View File

@ -20,33 +20,29 @@
package com.nextcloud.talk.jobs
import android.content.Context
import android.util.Log
import androidx.work.*
import androidx.work.CoroutineWorker
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import autodagger.AutoInjector
import com.bluelinelabs.logansquare.LoganSquare
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.events.EventStatus
import com.nextcloud.talk.jobs.WebsocketConnectionsWorker
import com.nextcloud.talk.models.ExternalSignalingServer
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.newarch.local.models.getCredentials
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
import com.nextcloud.talk.utils.database.user.UserUtils
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.greenrobot.eventbus.EventBus
import org.koin.core.KoinComponent
import org.koin.core.inject
import java.io.IOException
import java.util.*
import javax.inject.Inject
@ -63,7 +59,7 @@ class SignalingSettingsWorker(context: Context, workerParams: WorkerParameters)
?.inject(this)
val data = inputData
val internalUserId = data.getLong(KEY_INTERNAL_USER_ID, -1)
var userEntityList: MutableList<UserNgEntity?> = ArrayList<UserNgEntity?>()
var userEntityList: MutableList<UserNgEntity?> = ArrayList()
var userEntity: UserNgEntity?
if (internalUserId == -1L || usersRepository.getUserWithId(internalUserId) == null) {
userEntityList = usersRepository.getUsers().toMutableList()
@ -84,18 +80,18 @@ class SignalingSettingsWorker(context: Context, workerParams: WorkerParameters)
externalSignalingServer = ExternalSignalingServer()
externalSignalingServer.externalSignalingServer = signalingSettingsOverall.ocs.settings.externalSignalingServer
externalSignalingServer.externalSignalingTicket = signalingSettingsOverall.ocs.settings.externalSignalingTicket
val user = usersRepository.getUserWithId(userEntity.id)
val user = usersRepository.getUserWithId(userEntity.id!!)
user.externalSignaling = externalSignalingServer
runBlocking {
val result = usersRepository.updateUser(user)
eventBus.post(EventStatus(user.id,
eventBus.post(EventStatus(user.id!!,
EventStatus.EventType.SIGNALING_SETTINGS, result > 0))
}
}
override fun onError(e: Throwable) {
eventBus.post(EventStatus(finalUserEntity!!.id,
eventBus.post(EventStatus(finalUserEntity!!.id!!,
EventStatus.EventType.SIGNALING_SETTINGS, false))
}

View File

@ -53,4 +53,12 @@ class UsersRepositoryImpl(val usersDao: UsersDao): UsersRepository {
return usersDao.updateUser(user)
}
override suspend fun setUserAsActiveWithId(id: Long) {
usersDao.setUserAsActiveWithId(id)
}
override suspend fun deleteUserWithId(id: Long) {
usersDao.deleteUserWithId(id)
}
}

View File

@ -30,4 +30,6 @@ interface UsersRepository {
fun getUserWithId(id: Long): UserNgEntity
suspend fun getUserWithUsernameAndServer(username: String, server: String): UserNgEntity?
suspend fun updateUser(user: UserNgEntity): Int
suspend fun setUserAsActiveWithId(id: Long)
suspend fun deleteUserWithId(id: Long)
}

View File

@ -37,7 +37,6 @@ class ConversationListViewModelFactory constructor(
private val setConversationFavoriteValueUseCase: SetConversationFavoriteValueUseCase,
private val leaveConversationUseCase: LeaveConversationUseCase,
private val deleteConversationUseCase: DeleteConversationUseCase,
private val userUtils: UserUtils,
private val conversationsRepository: ConversationsRepository,
private val usersRepository: UsersRepository
) : ViewModelProvider.Factory {
@ -46,7 +45,7 @@ class ConversationListViewModelFactory constructor(
return ConversationsListViewModel(
application, conversationsUseCase,
setConversationFavoriteValueUseCase, leaveConversationUseCase, deleteConversationUseCase,
userUtils, conversationsRepository, usersRepository
conversationsRepository, usersRepository
) as T
}
}

View File

@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.text.InputType
import android.util.Log
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
@ -117,14 +118,18 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
}
settingsItem = menu.findItem(R.id.action_settings)
loadAvatar()
}
private fun loadAvatar() {
val iconSize = settingsItem?.icon?.intrinsicHeight?.toFloat()
?.let {
DisplayUtils.convertDpToPixel(
it,
activity!!
)
.toInt()
}
?.let {
DisplayUtils.convertDpToPixel(
it,
activity!!
)
.toInt()
}
iconSize?.let {
val target = object : Target {
@ -141,9 +146,9 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
viewModel.currentUserLiveData.value?.let {
val avatarRequest = Images().getRequestForUrl(
imageLoader, context, ApiUtils.getUrlForAvatarWithNameAndPixels(
it.baseUrl,
it.userId, iconSize
imageLoader, context, ApiUtils.getUrlForAvatarWithNameAndPixels(
it.baseUrl,
it.userId, iconSize
), it, target, this, CircleCropTransformation()
)
@ -214,6 +219,10 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
viewModel = viewModelProvider(factory).get(ConversationsListViewModel::class.java)
viewModel.apply {
currentUserLiveData.observe(this@ConversationsListView, Observer { value ->
loadAvatar()
})
viewState.observe(this@ConversationsListView, Observer { value ->
when (value) {
LOADING -> {
@ -363,8 +372,6 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
displayName
}
viewModel.loadConversations()
}
override fun onItemLongClick(position: Int) {
@ -443,7 +450,7 @@ class ConversationsListView : BaseView(), OnQueryTextListener,
bundle.putString(BundleKeys.KEY_ROOM_ID, conversation.conversationId)
bundle.putParcelable(BundleKeys.KEY_ACTIVE_CONVERSATION, Parcels.wrap(conversation))
ConductorRemapping.remapChatController(
router, viewModel.currentUserLiveData.value!!.id, conversation.token!!,
router, viewModel.currentUserLiveData.value!!.id!!, conversation.token!!,
bundle, false
)
}

View File

@ -54,7 +54,6 @@ class ConversationsListViewModel constructor(
private val setConversationFavoriteValueUseCase: SetConversationFavoriteValueUseCase,
private val leaveConversationUseCase: LeaveConversationUseCase,
private val deleteConversationUseCase: DeleteConversationUseCase,
private val userUtils: UserUtils,
private val conversationsRepository: ConversationsRepository,
usersRepository: UsersRepository
) : BaseViewModel<ConversationsListView>(application) {
@ -64,10 +63,7 @@ class ConversationsListViewModel constructor(
val searchQuery = MutableLiveData<String>()
val currentUserLiveData: LiveData<UserNgEntity> = usersRepository.getActiveUserLiveData()
val conversationsLiveData = Transformations.switchMap(currentUserLiveData) {
if (LOADING != viewState.value) {
viewState.value = LOADING
}
conversationsRepository.getConversationsForUser(it.id)
conversationsRepository.getConversationsForUser(it.id!!)
}
fun leaveConversation(conversation: Conversation) {
@ -82,7 +78,7 @@ class ConversationsListViewModel constructor(
object : UseCaseResponse<GenericOverall> {
override suspend fun onSuccess(result: GenericOverall) {
conversationsRepository.deleteConversation(
currentUserLiveData.value!!.id, conversation
currentUserLiveData.value!!.id!!, conversation
.conversationId!!
)
}
@ -111,7 +107,7 @@ class ConversationsListViewModel constructor(
object : UseCaseResponse<GenericOverall> {
override suspend fun onSuccess(result: GenericOverall) {
conversationsRepository.deleteConversation(
currentUserLiveData.value!!.id, conversation
currentUserLiveData.value!!.id!!, conversation
.conversationId!!
)
}
@ -142,7 +138,7 @@ class ConversationsListViewModel constructor(
object : UseCaseResponse<GenericOverall> {
override suspend fun onSuccess(result: GenericOverall) {
conversationsRepository.setFavoriteValueForConversation(
currentUserLiveData.value!!.id,
currentUserLiveData.value!!.id!!,
conversation.conversationId!!, favorite
)
}
@ -167,7 +163,7 @@ class ConversationsListViewModel constructor(
}
conversationsRepository.saveConversationsForUser(
internalUserId,
internalUserId!!,
mutableList)
messageData = ""
}
@ -258,7 +254,7 @@ class ConversationsListViewModel constructor(
value: Boolean
) {
conversationsRepository.setChangingValueForConversation(
currentUserLiveData.value!!.id, conversation
currentUserLiveData.value!!.id!!, conversation
.conversationId!!, value
)
}

View File

@ -42,7 +42,7 @@ val ConversationsListModule = module {
//viewModel { ConversationsListViewModel(get(), get()) }
factory {
createConversationListViewModelFactory(
androidApplication(), get(), get(), get(), get
androidApplication(), get(), get(), get
(), get(), get(), get()
)
}
@ -83,13 +83,12 @@ fun createConversationListViewModelFactory(
setConversationFavoriteValueUseCase: SetConversationFavoriteValueUseCase,
leaveConversationUseCase: LeaveConversationUseCase,
deleteConversationUseCase: DeleteConversationUseCase,
userUtils: UserUtils,
conversationsRepository: ConversationsRepository,
usersRepository: UsersRepository
): ConversationListViewModelFactory {
return ConversationListViewModelFactory(
application, getConversationsUseCase,
setConversationFavoriteValueUseCase, leaveConversationUseCase, deleteConversationUseCase,
userUtils, conversationsRepository, usersRepository
conversationsRepository, usersRepository
)
}

View File

@ -28,16 +28,20 @@ import com.nextcloud.talk.newarch.local.models.other.UserStatus.PENDING_DELETE
class UserStatusConverter {
@TypeConverter
fun fromUserStatusToInt(userStatus: UserStatus): Int {
fun fromUserStatusToInt(userStatus: UserStatus?): Int {
if (userStatus == null) {
return DORMANT.ordinal
}
return userStatus.ordinal
}
@TypeConverter
fun fromIntToUserStatus(value: Int): UserStatus {
when (value) {
0 -> return DORMANT
1 -> return ACTIVE
else -> return PENDING_DELETE
fun fromIntToUserStatus(value: Int): UserStatus? {
return when (value) {
0 -> DORMANT
1 -> ACTIVE
else -> PENDING_DELETE
}
}
}

View File

@ -21,47 +21,68 @@
package com.nextcloud.talk.newarch.local.dao
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import androidx.room.*
import com.nextcloud.talk.models.database.UserEntity
import com.nextcloud.talk.newarch.local.models.ConversationEntity
import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.newarch.local.models.other.UserStatus
@Dao
abstract class UsersDao {
// get active user
@Query("SELECT * FROM users where status = 1")
abstract fun getActiveUser(): UserNgEntity
// get active user
@Query("SELECT * FROM users where status = 1")
abstract fun getActiveUser(): UserNgEntity
@Query("SELECT * FROM users WHERE status = 1")
abstract fun getActiveUserLiveData(): LiveData<UserNgEntity>
@Query("SELECT * FROM users WHERE status = 1")
abstract fun getActiveUserLiveData(): LiveData<UserNgEntity>
@Query("DELETE FROM users WHERE id = :userId")
abstract fun deleteUserForId(userId: Long)
@Query("DELETE FROM users WHERE id = :id")
abstract suspend fun deleteUserWithId(id: Long)
@Update
abstract suspend fun updateUser(user: UserNgEntity): Int
@Update
abstract suspend fun updateUser(user: UserNgEntity): Int
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun saveUser(user: UserNgEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun saveUser(user: UserNgEntity): Long
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract suspend fun saveUsers(vararg users: UserNgEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract suspend fun saveUsers(vararg users: UserNgEntity)
// get all users not scheduled for deletion
@Query("SELECT * FROM users where status != 2")
abstract fun getUsers(): List<UserNgEntity>
// get all users not scheduled for deletion
@Query("SELECT * FROM users where status != 2")
abstract fun getUsers(): List<UserNgEntity>
@Query("SELECT * FROM users where id = :id")
abstract fun getUserWithId(id: Long): UserNgEntity
@Query("SELECT * FROM users where id = :id")
abstract fun getUserWithId(id: Long): UserNgEntity
@Query("SELECT * FROM users where status = 2")
abstract fun getUsersScheduledForDeletion(): List<UserNgEntity>
@Query("SELECT * FROM users where status = 2")
abstract fun getUsersScheduledForDeletion(): List<UserNgEntity>
@Query("SELECT * FROM users WHERE username = :username AND base_url = :server")
abstract suspend fun getUserWithUsernameAndServer(username: String, server: String): UserNgEntity?
@Query("SELECT * FROM users WHERE username = :username AND base_url = :server")
abstract suspend fun getUserWithUsernameAndServer(username: String, server: String): UserNgEntity?
@Transaction
open suspend fun setUserAsActiveWithId(id: Long) {
val users = getUsers()
for (user in users) {
if (user.id != id && UserStatus.ACTIVE == user.status) {
user.status = UserStatus.DORMANT
updateUser(user)
} else if (user.id == id && UserStatus.ACTIVE != user.status) {
user.status = UserStatus.ACTIVE
updateUser(user)
}
}
}
@Transaction
open suspend fun setAnyUserAsActive(): Boolean {
val users = getUsers()
for (user in users) {
user.status = UserStatus.ACTIVE
return true
}
return false
}
}

View File

@ -35,7 +35,7 @@ import kotlinx.android.parcel.RawValue
@Parcelize
@Entity(tableName = "users")
data class UserNgEntity(
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") var id: Long,
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") var id: Long?,
@ColumnInfo(name = "user_id") var userId: String,
@ColumnInfo(name = "username") var username: String,
@ColumnInfo(name = "base_url") var baseUrl: String,

View File

@ -297,7 +297,7 @@ class PushUtils(val usersRepository: UsersRepository) {
override fun onError(e: Throwable) {
eventBus!!.post(
EventStatus(
userEntity.id,
userEntity.id!!,
PUSH_REGISTRATION, false
)
)
@ -313,7 +313,7 @@ class PushUtils(val usersRepository: UsersRepository) {
override fun onError(e: Throwable) {
eventBus!!.post(
EventStatus(
userEntity.id,
userEntity.id!!,
PUSH_REGISTRATION,
false
)
@ -327,7 +327,7 @@ class PushUtils(val usersRepository: UsersRepository) {
override fun onError(e: Throwable) {
eventBus!!.post(
EventStatus(
userEntity.id,
userEntity.id!!,
PUSH_REGISTRATION,
false
)

View File

@ -275,6 +275,6 @@ class DatabaseStorageModule(
sharedApplication!!
.componentApplication
.inject(this)
accountIdentifier = conversationUser.id
accountIdentifier = conversationUser.id!!
}
}

View File

@ -253,7 +253,7 @@ class MagicWebSocketInstance internal constructor(
HashMap<String, String?>()
refreshChatHashMap[KEY_ROOM_TOKEN] = messageHashMap["roomid"] as String?
refreshChatHashMap[KEY_INTERNAL_USER_ID] =
java.lang.Long.toString(conversationUser.id)
java.lang.Long.toString(conversationUser.id!!)
eventBus.post(
WebSocketCommunicationEvent("refreshChat", refreshChatHashMap)
)

View File

@ -128,7 +128,7 @@ class WebSocketConnectionHelper: KoinComponent {
deleteExternalSignalingInstanceForUserEntity(userId)
}
magicWebSocketInstance = MagicWebSocketInstance(userEntity, generatedURL, webSocketTicket!!)
magicWebSocketInstanceMap[userEntity.id] = magicWebSocketInstance
magicWebSocketInstanceMap[userEntity.id!!] = magicWebSocketInstance
return magicWebSocketInstance
}
}

View File

@ -29,7 +29,7 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=2048m
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=4096m
android.useAndroidX=true
android.enableJetifier=true