From 44fe006603d54b8b3de7a4ba8c4609d9763f7c9e Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 1 Aug 2019 15:26:47 +0200 Subject: [PATCH 01/10] wip --- vector/src/main/java/im/vector/VectorApp.java | 4 ++ .../vector/activity/VectorRoomActivity.java | 46 +++++++++++++- .../im/vector/util/PreferencesManager.java | 6 ++ .../java/im/vector/util/TermsAcceptUtils.kt | 60 +++++++++++++++++++ vector/src/main/res/values/strings.xml | 4 ++ 5 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 vector/src/main/java/im/vector/util/TermsAcceptUtils.kt diff --git a/vector/src/main/java/im/vector/VectorApp.java b/vector/src/main/java/im/vector/VectorApp.java index 3d319b1680..686d3e895d 100755 --- a/vector/src/main/java/im/vector/VectorApp.java +++ b/vector/src/main/java/im/vector/VectorApp.java @@ -192,6 +192,10 @@ public void onReceive(Context context, Intent intent) { @Override public void onCreate() { Log.d(LOG_TAG, "onCreate"); +// PreferencesManager.setIntegrationServerUrls(this,"https://scolar.vectir.im/", +// "https://scolar.vectir.im/","https://scolar.vectir.im/"); + PreferencesManager.setIntegrationServerUrls(this,getString(R.string.integrations_ui_url), + getString(R.string.integrations_rest_url),getString(R.string.integrations_jitsi_widget_url)); super.onCreate(); mLifeCycleListener = new VectorLifeCycleObserver(); diff --git a/vector/src/main/java/im/vector/activity/VectorRoomActivity.java b/vector/src/main/java/im/vector/activity/VectorRoomActivity.java index 4b437bb965..3ec9865311 100755 --- a/vector/src/main/java/im/vector/activity/VectorRoomActivity.java +++ b/vector/src/main/java/im/vector/activity/VectorRoomActivity.java @@ -126,6 +126,7 @@ import im.vector.util.ReadMarkerManager; import im.vector.util.RoomUtils; import im.vector.util.SlashCommandsParser; +import im.vector.util.TermsAcceptUtilsKt; import im.vector.util.VectorMarkdownParser; import im.vector.util.VectorRoomMediasSender; import im.vector.util.VectorUtils; @@ -1634,9 +1635,28 @@ private void openIntegrationManagerActivity(@Nullable String screenId) { if (mRoom == null) { return; } - final Intent intent = IntegrationManagerActivity.Companion.getIntent(this, mMyUserId, mRoom.getRoomId(), null, screenId); - startActivity(intent); + TermsAcceptUtilsKt.checkTermsForIntegrationMgr(this, mSession, intent, null); +// WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(this); +// if (wm == null) { +// //Should not happen this action is not activated if no wm +// return; +// } +// if (PreferencesManager.hasAgreedToIntegrationManager(this, mSession.getMyUserId(), wm.getUIUrl())) { +// final Intent intent = IntegrationManagerActivity.Companion.getIntent(this, mMyUserId, mRoom.getRoomId(), null, screenId); +// startActivity(intent); +// } else { +// //Need to ask for consent +// new AlertDialog.Builder(this) +// .setTitle(R.string.widget_integration_accept_terms_dialog_title) +// .setMessage(R.string.widget_integration_accept_terms_dialog_message) +// .setIcon(android.R.drawable.ic_dialog_alert) +// .setNeutralButton(R.string.review, null) +// .setPositiveButton(R.string.accept, null) +// .setNegativeButton(R.string.decline, null) +// .show(); +// } + } /** @@ -2281,6 +2301,23 @@ private void launchFileSelectionIntent() { } private void startStickerPickerActivity() { +// WidgetsManager wm = WidgetManagerProvider.INSTANCE.getWidgetManager(this); +// if (wm == null) { +// //Should not happen this action is not activated if no wm +// return; +// } +// if (!PreferencesManager.hasAgreedToIntegrationManager(this, mSession.getMyUserId(), wm.getUIUrl())) { +// //Need to ask for consent +// new AlertDialog.Builder(this) +// .setTitle(R.string.widget_integration_accept_terms_dialog_title) +// .setMessage(R.string.widget_integration_accept_terms_dialog_message) +// .setIcon(android.R.drawable.ic_dialog_alert) +// .setNeutralButton(R.string.review, null) +// .setPositiveButton(R.string.accept, null) +// .setNegativeButton(R.string.decline, null) +// .show(); +// return; +// } // Search for the sticker picker widget in the user account Map userWidgets = mSession.getUserWidgets(); @@ -2325,9 +2362,12 @@ public void onClick(DialogInterface dialog, int which) { } Intent intent = StickerPickerActivity.Companion.getIntent(this, mMyUserId, mRoom.getRoomId(), stickerWidgetUrl, stickerWidgetId); + TermsAcceptUtilsKt.checkTermsForIntegrationMgr(this, mSession, intent, RequestCodesKt.STICKER_PICKER_ACTIVITY_REQUEST_CODE); - startActivityForResult(intent, RequestCodesKt.STICKER_PICKER_ACTIVITY_REQUEST_CODE); +// Intent intent = StickerPickerActivity.Companion.getIntent(this, mMyUserId, mRoom.getRoomId(), stickerWidgetUrl, stickerWidgetId); +// startActivityForResult(intent, RequestCodesKt.STICKER_PICKER_ACTIVITY_REQUEST_CODE); } + } /** diff --git a/vector/src/main/java/im/vector/util/PreferencesManager.java b/vector/src/main/java/im/vector/util/PreferencesManager.java index 875205331e..1261361431 100755 --- a/vector/src/main/java/im/vector/util/PreferencesManager.java +++ b/vector/src/main/java/im/vector/util/PreferencesManager.java @@ -168,6 +168,7 @@ public class PreferencesManager { public static final String SETTINGS_INTEGRATION_MANAGER_API_URL = "SETTINGS_INTEGRATION_MANAGER_API_URL"; public static final String SETTINGS_INTEGRATION_MANAGER_JITSI_URL = "SETTINGS_INTEGRATION_MANAGER_JITSI_URL"; public static final String SETTINGS_INTEGRATION_WHITELIST_URL = "SETTINGS_INTEGRATION_WHITELIST_URL"; + public static final String SETTINGS_INTEGRATION_AGREEMENT_PREFIX = "SETTINGS_INTEGRATION_AGREEMENT_PREFIX_"; // other public static final String SETTINGS_MEDIA_SAVING_PERIOD_KEY = "SETTINGS_MEDIA_SAVING_PERIOD_KEY"; @@ -576,6 +577,11 @@ public static boolean useJitsiConfCall(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_USE_JITSI_CONF_PREFERENCE_KEY, true); } + public static boolean hasAgreedToIntegrationManager(Context context, String userID, String integrationMgrServer) { + return PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(SETTINGS_INTEGRATION_AGREEMENT_PREFIX + userID + "_" + integrationMgrServer, false); + } + /** * Tells if the application is started on boot * diff --git a/vector/src/main/java/im/vector/util/TermsAcceptUtils.kt b/vector/src/main/java/im/vector/util/TermsAcceptUtils.kt new file mode 100644 index 0000000000..cbe50d0a9b --- /dev/null +++ b/vector/src/main/java/im/vector/util/TermsAcceptUtils.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.util + +import android.app.Activity +import android.content.Intent +import android.support.v7.app.AlertDialog +import im.vector.R +import im.vector.widgets.WidgetManagerProvider +import org.matrix.androidsdk.MXSession + + +fun checkTermsForIntegrationMgr(activity: Activity, session: MXSession, successIntent: Intent, requestCode: Int?) { + val wm = WidgetManagerProvider.getWidgetManager(activity) ?: return + if (PreferencesManager.hasAgreedToIntegrationManager(activity, session.myUserId, wm.uiUrl)) { + if (requestCode != null) { + activity.startActivityForResult(successIntent, requestCode) + } else { + activity.startActivity(successIntent) + } + } else { + //Need to ask for consent + val dialog = AlertDialog.Builder(activity) + .setTitle(R.string.widget_integration_accept_terms_dialog_title) + .setMessage(R.string.widget_integration_accept_terms_dialog_message) + .setIcon(android.R.drawable.ic_dialog_alert) + .setNeutralButton(R.string.review, null) + .setPositiveButton(R.string.accept) { _, _ -> + if (requestCode != null) { + activity.startActivityForResult(successIntent, requestCode) + } else { + activity.startActivity(successIntent) + } + } + .setNegativeButton(R.string.decline, null) + .create() + + //On tap review we don't close the dialog + dialog.setOnShowListener { + dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener { + openUrlInExternalBrowser(activity, "https://example.org/tos/v1/fr.html") + } + } + dialog.show() + } +} \ No newline at end of file diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index c701387dc1..743d860af7 100755 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -95,6 +95,8 @@ Done Abort Ignore + Review + Decline Exit @@ -1099,6 +1101,8 @@ Use keyboard enter key to send message Send voice messages This option requires a third party application to record the messages. + Accept to continue + You must accept the Terms of Service to use bots, bridgets widgets & sticker packs. You added a new device \'%s\', which is requesting encryption keys. From eedd895205db170375ddd57b32c5613bda073dbf Mon Sep 17 00:00:00 2001 From: Valere Date: Sat, 3 Aug 2019 11:30:21 +0200 Subject: [PATCH 02/10] WIP / Accept terms screens --- vector/src/main/AndroidManifest.xml | 4 + .../im/vector/activity/ReviewTermsActivity.kt | 32 +++++ .../vector/activity/VectorRoomActivity.java | 2 +- .../fragments/terms/AcceptTermsFragment.kt | 112 ++++++++++++++++++ .../fragments/terms/AcceptTermsViewModel.kt | 49 ++++++++ .../terms}/TermsAcceptUtils.kt | 4 +- .../vector/fragments/terms/TermsController.kt | 29 +++++ .../im/vector/fragments/terms/TermsModel.kt | 66 +++++++++++ .../res/layout/activity_single_fragment.xml | 6 + .../main/res/layout/fragment_accept_terms.xml | 47 ++++++++ vector/src/main/res/layout/item_tos.xml | 63 ++++++++++ vector/src/main/res/values/strings.xml | 4 + 12 files changed, 416 insertions(+), 2 deletions(-) create mode 100644 vector/src/main/java/im/vector/activity/ReviewTermsActivity.kt create mode 100644 vector/src/main/java/im/vector/fragments/terms/AcceptTermsFragment.kt create mode 100644 vector/src/main/java/im/vector/fragments/terms/AcceptTermsViewModel.kt rename vector/src/main/java/im/vector/{util => fragments/terms}/TermsAcceptUtils.kt (95%) create mode 100644 vector/src/main/java/im/vector/fragments/terms/TermsController.kt create mode 100644 vector/src/main/java/im/vector/fragments/terms/TermsModel.kt create mode 100644 vector/src/main/res/layout/activity_single_fragment.xml create mode 100644 vector/src/main/res/layout/fragment_accept_terms.xml create mode 100644 vector/src/main/res/layout/item_tos.xml diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 0f7d6618f8..d2a79bf0f8 100755 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -433,6 +433,10 @@ android:name=".activity.SASVerificationActivity" android:label="@string/title_activity_verify_device" android:windowSoftInputMode="stateHidden|adjustResize" /> + { + override fun onSuccess(info: TermsResponse?) { + val terms = ArrayList() + info?.getLocalizedPrivacyPolicies()?.let { + Log.e("FOO",it.localizedUrl) + terms.add( + Term(it.localizedUrl ?: "", + it.localizedName ?: "", + "Utiliser des robots, des passerelles, des widgets ou des packs de stickers") + ) + } + info?.getLocalizedTermOfServices()?.let { + Log.e("FOO",it.localizedUrl) + terms.add( + Term(it.localizedUrl ?: "", + it.localizedName ?: "", + "Utiliser des robots, des passerelles, des widgets ou des packs de stickers") + ) + } + viewModel.termsList.postValue(terms) + } + + override fun onUnexpectedError(e: Exception?) {} + + override fun onNetworkError(e: Exception?) {} + + override fun onMatrixError(e: MatrixError?) {} + + }) + +// val terms = listOf( +// Term("https://example.org/somewhere/privacy-1.2-fr.html", +// "Gestionnaire d’intégrations", +// "Utiliser des robots, des passerelles, des widgets ou des packs de stickers\n" + +// "(Politique de confidentialité)"), +// +// Term("https://example.org/somewhere/terms-2.0-fr.html", +// "Gestionnaire d’intégrations", +// "Utiliser des robots, des passerelles, des widgets ou des packs de stickers\n" + +// "(Conditions d'utilisation)") +// ) +// viewModel.termsList.postValue(terms) + + + viewModel.termsList.observe(this, Observer { terms -> + if (terms != null) { + updateState(terms) + acceptButton.isEnabled = terms.all { it.accepted } + } + }) + } + + private fun updateState(terms: List) { + termsController.setData(terms) + } + + companion object { + fun newInstance(): AcceptTermsFragment { + return AcceptTermsFragment() + } + } + + override fun setChecked(term: Term, isChecked: Boolean) { + viewModel.acceptTerm(term.url,isChecked) + } + + override fun review(term: Term) { + openUrlInExternalBrowser(this.requireContext(), term.url) + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/fragments/terms/AcceptTermsViewModel.kt b/vector/src/main/java/im/vector/fragments/terms/AcceptTermsViewModel.kt new file mode 100644 index 0000000000..ae285b24dd --- /dev/null +++ b/vector/src/main/java/im/vector/fragments/terms/AcceptTermsViewModel.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.fragments.terms + +import android.arch.lifecycle.MutableLiveData +import android.arch.lifecycle.ViewModel + +class AcceptTermsViewModel : ViewModel() { + + var termsList: MutableLiveData> = MutableLiveData() + + fun acceptTerm(url: String, accepted: Boolean) { + + termsList.value?.map { + if (it.url == url) { + it.copy(accepted = accepted) + } else it + }?.let { + termsList.postValue(it) + } + } + + fun reviewTerm(url: String) { + + } + + +} + +data class Term ( + val url: String, + val name: String, + val description: String? = null, + val version: String? = null, + val accepted: Boolean = false +) \ No newline at end of file diff --git a/vector/src/main/java/im/vector/util/TermsAcceptUtils.kt b/vector/src/main/java/im/vector/fragments/terms/TermsAcceptUtils.kt similarity index 95% rename from vector/src/main/java/im/vector/util/TermsAcceptUtils.kt rename to vector/src/main/java/im/vector/fragments/terms/TermsAcceptUtils.kt index cbe50d0a9b..ebdb3bb54c 100644 --- a/vector/src/main/java/im/vector/util/TermsAcceptUtils.kt +++ b/vector/src/main/java/im/vector/fragments/terms/TermsAcceptUtils.kt @@ -14,12 +14,14 @@ * limitations under the License. */ -package im.vector.util +package im.vector.fragments.terms import android.app.Activity import android.content.Intent import android.support.v7.app.AlertDialog import im.vector.R +import im.vector.util.PreferencesManager +import im.vector.util.openUrlInExternalBrowser import im.vector.widgets.WidgetManagerProvider import org.matrix.androidsdk.MXSession diff --git a/vector/src/main/java/im/vector/fragments/terms/TermsController.kt b/vector/src/main/java/im/vector/fragments/terms/TermsController.kt new file mode 100644 index 0000000000..ab98bbeba8 --- /dev/null +++ b/vector/src/main/java/im/vector/fragments/terms/TermsController.kt @@ -0,0 +1,29 @@ +package im.vector.fragments.terms + +import android.view.View +import com.airbnb.epoxy.TypedEpoxyController + +class TermsController(private val listener: TermsController.Listener) : TypedEpoxyController>() { + + override fun buildModels(data: List?) { + data?.forEach { term -> + terms { + id(term.url) + name(term.name) + description(term.description) + checked(term.accepted) + + + clickListener(View.OnClickListener { listener.review(term) }) + checkChangeListener { _, isChecked -> + listener.setChecked(term, isChecked) + } + } + } + } + + interface Listener { + fun setChecked(term: Term, isChecked: Boolean) + fun review(term: Term) + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/fragments/terms/TermsModel.kt b/vector/src/main/java/im/vector/fragments/terms/TermsModel.kt new file mode 100644 index 0000000000..b03c6278c4 --- /dev/null +++ b/vector/src/main/java/im/vector/fragments/terms/TermsModel.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.fragments.terms + +import android.view.View +import android.widget.CheckBox +import android.widget.CompoundButton +import android.widget.TextView +import butterknife.BindView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import com.airbnb.epoxy.EpoxyModelWithHolder +import im.vector.R +import im.vector.ui.epoxy.BaseEpoxyHolder + +@EpoxyModelClass(layout = R.layout.item_tos) +abstract class TermsModel : EpoxyModelWithHolder() { + + @EpoxyAttribute + var checked: Boolean = false + + @EpoxyAttribute + var name: String? = null + + @EpoxyAttribute + var description: String? = null + + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) + var checkChangeListener: CompoundButton.OnCheckedChangeListener? = null + + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) + var clickListener: View.OnClickListener? = null + + override fun bind(holder: Holder) { + holder.checkbox.isChecked = checked + holder.title.text = name + holder.description.text = description + holder.checkbox.setOnCheckedChangeListener(checkChangeListener) + holder.main.setOnClickListener(clickListener) + } + + class Holder : BaseEpoxyHolder() { + @BindView(R.id.term_accept_checkbox) + lateinit var checkbox: CheckBox + + @BindView(R.id.term_name) + lateinit var title: TextView + + @BindView(R.id.term_description) + lateinit var description: TextView + } +} \ No newline at end of file diff --git a/vector/src/main/res/layout/activity_single_fragment.xml b/vector/src/main/res/layout/activity_single_fragment.xml new file mode 100644 index 0000000000..f9504c9a46 --- /dev/null +++ b/vector/src/main/res/layout/activity_single_fragment.xml @@ -0,0 +1,6 @@ + + + + diff --git a/vector/src/main/res/layout/fragment_accept_terms.xml b/vector/src/main/res/layout/fragment_accept_terms.xml new file mode 100644 index 0000000000..00bd1bfb32 --- /dev/null +++ b/vector/src/main/res/layout/fragment_accept_terms.xml @@ -0,0 +1,47 @@ + + + + + + + + +