Skip to content

Commit

Permalink
ToS
Browse files Browse the repository at this point in the history
Signed-off-by: tobiasKaminsky <[email protected]>
  • Loading branch information
tobiasKaminsky committed Feb 5, 2025
1 parent a4038fe commit 31b58d0
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.nextcloud.ui.SetStatusDialogFragment;
import com.nextcloud.ui.composeActivity.ComposeActivity;
import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
import com.nextcloud.ui.trashbinFileActions.TrashbinFileActionsBottomSheet;
import com.nmc.android.ui.LauncherActivity;
import com.owncloud.android.MainApp;
import com.owncloud.android.authentication.AuthenticatorActivity;
Expand Down Expand Up @@ -97,6 +98,7 @@
import com.owncloud.android.ui.dialog.StoragePermissionDialogFragment;
import com.owncloud.android.ui.dialog.SyncFileNotEnoughSpaceDialogFragment;
import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment;
import com.owncloud.android.ui.dialog.TermsOfServiceDialog;
import com.owncloud.android.ui.dialog.setupEncryption.SetupEncryptionDialogFragment;
import com.owncloud.android.ui.fragment.ExtendedListFragment;
import com.owncloud.android.ui.fragment.FeatureFragment;
Expand Down Expand Up @@ -124,7 +126,6 @@
import com.owncloud.android.ui.preview.PreviewTextFragment;
import com.owncloud.android.ui.preview.PreviewTextStringFragment;
import com.owncloud.android.ui.preview.pdf.PreviewPdfFragment;
import com.nextcloud.ui.trashbinFileActions.TrashbinFileActionsBottomSheet;
import com.owncloud.android.ui.trashbin.TrashbinActivity;

import androidx.annotation.OptIn;
Expand Down Expand Up @@ -502,4 +503,6 @@ abstract class ComponentsModule {
@ContributesAndroidInjector
abstract BackgroundPlayerService backgroundPlayerService();

@ContributesAndroidInjector
abstract TermsOfServiceDialog termsOfServiceDialog();
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
import com.owncloud.android.ui.dialog.SendShareDialog;
import com.owncloud.android.ui.dialog.SortingOrderDialogFragment;
import com.owncloud.android.ui.dialog.StoragePermissionDialogFragment;
import com.owncloud.android.ui.dialog.TermsOfServiceDialog;
import com.owncloud.android.ui.events.SearchEvent;
import com.owncloud.android.ui.events.SyncEventFinished;
import com.owncloud.android.ui.events.TokenPushEvent;
Expand Down Expand Up @@ -153,6 +154,7 @@
import javax.inject.Inject;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.SearchView;
Expand Down Expand Up @@ -202,6 +204,7 @@ public class FileDisplayActivity extends FileActivity
private static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
private static final String KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS";
private static final String KEY_WAITING_TO_SEND = "WAITING_TO_SEND";
private static final String DIALOG_TAG_SHOW_TOS = "DIALOG_TAG_SHOW_TOS";

public static final String ACTION_DETAILS = "com.owncloud.android.ui.activity.action.DETAILS";

Expand Down Expand Up @@ -773,11 +776,11 @@ public void showFileActions(OCFile file) {
listOfFiles.onOverflowIconClicked(file, null);
}

public @androidx.annotation.Nullable Fragment getLeftFragment() {
public @Nullable Fragment getLeftFragment() {
return getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_LIST_OF_FILES);
}

public @androidx.annotation.Nullable
public @Nullable
@Deprecated OCFileListFragment getListOfFilesFragment() {
Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_LIST_OF_FILES);
if (listOfFiles instanceof OCFileListFragment) {
Expand Down Expand Up @@ -1433,6 +1436,11 @@ public void onReceive(Context context, Intent intent) {
case HOST_NOT_AVAILABLE:
showInfoBox(R.string.host_not_available);
break;

case SIGNING_TOS_NEEDED:
showTermsOfServiceDialog();

break;

default:
// nothing to do
Expand Down Expand Up @@ -1477,6 +1485,11 @@ public void onReceive(Context context, Intent intent) {
}
}
}
private void showTermsOfServiceDialog() {
if (getSupportFragmentManager().findFragmentByTag(DIALOG_TAG_SHOW_TOS) == null) {
new TermsOfServiceDialog().show(getSupportFragmentManager(), DIALOG_TAG_SHOW_TOS);
}
}

private boolean checkForRemoteOperationError(RemoteOperationResult syncResult) {
return ResultCode.UNAUTHORIZED == syncResult.getCode() || (syncResult.isException() && syncResult.getException() instanceof AuthenticatorException);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2025 Tobias Kaminsky <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.owncloud.android.ui.dialog

import android.app.Dialog
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.core.app.ActivityCompat.finishAffinity
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.nextcloud.android.lib.resources.tos.GetTermsRemoteOperation
import com.nextcloud.android.lib.resources.tos.SignTermRemoteOperation
import com.nextcloud.android.lib.resources.tos.Term
import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.di.Injectable
import com.nextcloud.client.network.ClientFactory
import com.nextcloud.common.NextcloudClient
import com.nextcloud.utils.extensions.setHtmlContent
import com.owncloud.android.R
import com.owncloud.android.databinding.DialogShowTosBinding
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.utils.DisplayUtils
import com.owncloud.android.utils.theme.ViewThemeUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject

class TermsOfServiceDialog : DialogFragment(), Injectable {
private lateinit var binding: DialogShowTosBinding

@Inject
lateinit var clientFactory: ClientFactory

@Inject
lateinit var accountManager: UserAccountManager

@Inject
lateinit var viewThemeUtils: ViewThemeUtils

lateinit var client: NextcloudClient
lateinit var terms: List<Term>
lateinit var languages: Map<String, String>

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

fetchTerms()
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
binding = DialogShowTosBinding.inflate(requireActivity().layoutInflater)

return createDialogBuilder().create()
}

private fun updateDialog() {
binding.message.setHtmlContent(terms[0].renderedBody)

val arrayAdapter: ArrayAdapter<String> = ArrayAdapter(
binding.root.context,
android.R.layout.simple_spinner_item
)

for ((_, _, languageCode) in terms) {
arrayAdapter.add(languages[languageCode])
}

arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)

binding.languageDropdown.adapter = arrayAdapter
binding.languageDropdown.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>?, view: View, position: Int, l: Long) {
binding.message
.setHtmlContent(terms[position].renderedBody)
}

override fun onNothingSelected(adapterView: AdapterView<*>?) = Unit
}

if (terms.size == 1) {
binding.languageDropdown.visibility = View.GONE
}
}

private fun fetchTerms() {
// TODO use viewLifecycleOwner instead
CoroutineScope(Dispatchers.IO).launch {
try {
client = clientFactory.createNextcloudClient(accountManager.getUser())
val result = GetTermsRemoteOperation().execute(client)

if (result.isSuccess &&
!result.resultData.hasSigned &&
result.resultData.terms.isNotEmpty()
) {
languages = result.resultData.languages
terms = result.resultData.terms

withContext(Dispatchers.Main) {
updateDialog()
}
}
} catch (exception: ClientFactory.CreationException) {
Log_OC.e(TAG, "Error creating client!")
}
}
}

private fun createDialogBuilder(): MaterialAlertDialogBuilder {
return MaterialAlertDialogBuilder(binding.root.context)
.setView(binding.root)
.setTitle(R.string.terms_of_service_title)
.setNegativeButton(R.string.dialog_close) { _, _ ->
activity?.let { finishAffinity(it) }
}
.setPositiveButton(R.string.terms_of_services_agree) { dialog, _ ->
dialog.dismiss()
Thread {
val id = binding.languageDropdown.selectedItemPosition
val signResult: RemoteOperationResult<Void> =
SignTermRemoteOperation(terms.get(id).id).execute(client)
if (!signResult.isSuccess) {
DisplayUtils.showSnackMessage(view, R.string.sign_tos_failed)
}
}.start()
}
}

companion object {
private const val TAG = "TermsOfServiceDialog"
}
}
37 changes: 37 additions & 0 deletions app/src/main/res/layout/dialog_show_tos.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Nextcloud - Android Client
~
~ SPDX-FileCopyrightText: 2022 Álvaro Brey <[email protected]>
~ SPDX-FileCopyrightText: 2022 Nextcloud GmbH
~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false"
android:focusable="true"
android:orientation="vertical"
android:paddingHorizontal="?dialogPreferredPadding">

<Spinner
android:id="@+id/language_dropdown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end" />

<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</ScrollView>
</LinearLayout>
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1310,4 +1310,8 @@
<item quantity="one">%1$d download remaining</item>
<item quantity="other">%1$d downloads remaining</item>
</plurals>
<string name="sign_tos_needed">Please sign ToS</string>
<string name="sign_tos_failed">Please manually check terms of service!</string>
<string name="terms_of_service_title">Terms of service</string>
<string name="terms_of_services_agree">I agree to the above ToS</string>
</resources>
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/
buildscript {
ext {
androidLibraryVersion ="a885642fdd45c076c303e86eea33c7a7b1e91858"
androidLibraryVersion = "8f6d922b05437166ba187e2f68c5db3a29bc0727"
androidPluginVersion = '8.8.0'
androidxMediaVersion = '1.5.1'
androidxTestVersion = "1.6.1"
Expand Down
19 changes: 19 additions & 0 deletions gradle/verification-metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9241,6 +9241,14 @@
<sha256 value="1bf1482df26848a59743a94ea6ee53d4ef6f014af5a21274214ab62eb2c6a8d6" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="com.github.nextcloud" name="android-library" version="5fe34e4a90fc49612ffd94411b5b39f97235c992">
<artifact name="android-library-5fe34e4a90fc49612ffd94411b5b39f97235c992.aar">
<sha256 value="ebc753d2b655bd0fb46a89dc2e359ec9eb6e8e790fd77376cb4667762efc2d1e" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="android-library-5fe34e4a90fc49612ffd94411b5b39f97235c992.module">
<sha256 value="5ed87fb9c467d68e9f6edf716bf4142f52a360b888026676667d25cfca7f2d79" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="com.github.nextcloud" name="android-library" version="638326e14bc234ca3285852af461d41e6e08d1aa">
<artifact name="android-library-638326e14bc234ca3285852af461d41e6e08d1aa.aar">
<sha256 value="7026ad9ce3b66726f71b97acd19b6aa104ab38cf0b072ccd624900878e5e48bf" origin="Generated by Gradle" reason="Artifact is not signed"/>
Expand Down Expand Up @@ -9321,6 +9329,17 @@
<sha256 value="8311ad1fd1507e6184ff6a9f019ad13dc03075ae467936e1540c43993fd18ed4" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="com.github.nextcloud" name="android-library"
version="8f6d922b05437166ba187e2f68c5db3a29bc0727">
<artifact name="android-library-8f6d922b05437166ba187e2f68c5db3a29bc0727.aar">
<sha256 value="c6dbef694d7c4a3264f38b860afaf2a7cb8be2ed063b53741d3ab7a375051b6d"
origin="Generated by Gradle" reason="Artifact is not signed" />
</artifact>
<artifact name="android-library-8f6d922b05437166ba187e2f68c5db3a29bc0727.module">
<sha256 value="ed3adfc1e8120360bdaa26c4d0337c54d288cbb2ca215cf07c38d034ae853fcc"
origin="Generated by Gradle" reason="Artifact is not signed" />
</artifact>
</component>
<component group="com.github.nextcloud" name="android-library" version="9fdcd0af0ff910086281f32e3b8ef74490671149">
<artifact name="android-library-9fdcd0af0ff910086281f32e3b8ef74490671149.aar">
<sha256 value="57ab4fd7c922875a7e0b5feac20aa27ab5df0fd3b4e042f92ed727c0b6316e81" origin="Generated by Gradle" reason="Artifact is not signed"/>
Expand Down

0 comments on commit 31b58d0

Please sign in to comment.