mirror of https://github.com/nextcloud/android
Merge master
Signed-off-by: alperozturk <alper_ozturk@proton.me>
This commit is contained in:
commit
c48baf71f8
|
@ -32,7 +32,7 @@ jobs:
|
|||
with:
|
||||
swap-size-gb: 10
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5
|
||||
uses: github/codeql-action/init@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Set up JDK 17
|
||||
|
@ -46,4 +46,4 @@ jobs:
|
|||
echo "org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError" > "$HOME/.gradle/gradle.properties"
|
||||
./gradlew assembleDebug
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5
|
||||
uses: github/codeql-action/analyze@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
|
||||
|
|
|
@ -37,6 +37,6 @@ jobs:
|
|||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5
|
||||
uses: github/codeql-action/upload-sarif@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
|
|
@ -84,8 +84,8 @@ android {
|
|||
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 33
|
||||
compileSdk 33
|
||||
targetSdkVersion 34
|
||||
compileSdk 34
|
||||
|
||||
buildConfigField 'boolean', 'CI', ciBuild.toString()
|
||||
buildConfigField 'boolean', 'RUNTIME_PERF_ANALYSIS', perfAnalysis.toString()
|
||||
|
@ -246,7 +246,7 @@ dependencies {
|
|||
implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5' // remove after entire switch to lib v2
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'com.google.android.material:material:1.9.0'
|
||||
implementation 'com.google.android.material:material:1.10.0'
|
||||
implementation 'com.jakewharton:disklrucache:2.0.2'
|
||||
implementation "androidx.appcompat:appcompat:$appCompatVersion"
|
||||
implementation 'androidx.webkit:webkit:1.7.0'
|
||||
|
|
|
@ -174,7 +174,7 @@ class ActivitiesActivityIT : AbstractIT() {
|
|||
sut.dismissSnackbar()
|
||||
}
|
||||
|
||||
shortSleep()
|
||||
longSleep()
|
||||
waitForIdleSync()
|
||||
|
||||
screenshot(sut)
|
||||
|
|
|
@ -20,14 +20,15 @@
|
|||
*/
|
||||
package com.owncloud.android.ui.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
|
||||
/**
|
||||
* Activity providing information about ways to participate in the app's development.
|
||||
*/
|
||||
class HuaweiCommunityActivity : CommunityActivity() {
|
||||
override fun setupContent() {
|
||||
super.setupContent()
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding.communityReleaseCandidatePlaystore.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ abstract class NextcloudDatabase : RoomDatabase() {
|
|||
INSTANCE = Room
|
||||
.databaseBuilder(context, NextcloudDatabase::class.java, ProviderMeta.DB_NAME)
|
||||
.allowMainThreadQueries()
|
||||
.addLegacyMigrations(clock)
|
||||
.addLegacyMigrations(clock, context)
|
||||
.addMigrations(RoomMigration())
|
||||
.addMigrations(Migration67to68())
|
||||
.addMigrations(Migration70to71())
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
package com.nextcloud.client.database.migrations
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
@ -36,12 +37,13 @@ private const val MIN_SUPPORTED_DB_VERSION = 24
|
|||
class LegacyMigration(
|
||||
private val from: Int,
|
||||
private val to: Int,
|
||||
private val clock: Clock
|
||||
private val clock: Clock,
|
||||
private val context: Context
|
||||
) : Migration(from, to) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
LegacyMigrationHelper(clock)
|
||||
.onUpgrade(database, from, to)
|
||||
LegacyMigrationHelper(clock, context)
|
||||
.tryUpgrade(database, from, to)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,10 +54,11 @@ class LegacyMigration(
|
|||
*/
|
||||
@Suppress("ForEachOnRange")
|
||||
fun RoomDatabase.Builder<NextcloudDatabase>.addLegacyMigrations(
|
||||
clock: Clock
|
||||
clock: Clock,
|
||||
context: Context
|
||||
): RoomDatabase.Builder<NextcloudDatabase> {
|
||||
(MIN_SUPPORTED_DB_VERSION until NextcloudDatabase.FIRST_ROOM_DB_VERSION - 1)
|
||||
.map { from -> LegacyMigration(from, from + 1, clock) }
|
||||
.map { from -> LegacyMigration(from, from + 1, clock, context) }
|
||||
.forEach { migration -> this.addMigrations(migration) }
|
||||
return this
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
package com.nextcloud.client.database.migrations;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
|
@ -31,11 +32,11 @@ import com.owncloud.android.datamodel.SyncedFolder;
|
|||
import com.owncloud.android.db.ProviderMeta;
|
||||
import com.owncloud.android.files.services.NameCollisionPolicy;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.providers.FileContentProvider;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
public class LegacyMigrationHelper {
|
||||
|
||||
|
@ -52,12 +53,29 @@ public class LegacyMigrationHelper {
|
|||
private static final String UPGRADE_VERSION_MSG = "OUT of the ADD in onUpgrade; oldVersion == %d, newVersion == %d";
|
||||
|
||||
private final Clock clock;
|
||||
private final Context context;
|
||||
|
||||
public LegacyMigrationHelper(Clock clock) {
|
||||
public LegacyMigrationHelper(Clock clock, Context context) {
|
||||
this.clock = clock;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
public void tryUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
try {
|
||||
upgrade(db, oldVersion, newVersion);
|
||||
} catch (Throwable t) {
|
||||
Log_OC.i(TAG, "Migration upgrade failed due to " + t);
|
||||
clearStorage();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
|
||||
private void clearStorage() {
|
||||
context.getCacheDir().delete();
|
||||
((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).clearApplicationUserData();
|
||||
}
|
||||
|
||||
private void upgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log_OC.i(TAG, "Entering in onUpgrade");
|
||||
boolean upgraded = false;
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Alper Ozturk
|
||||
* Copyright (C) 2023 Alper Ozturk
|
||||
* Copyright (C) 2023 Nextcloud GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.nextcloud.utils.extensions
|
||||
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.widget.TextView
|
||||
import androidx.core.text.HtmlCompat
|
||||
|
||||
@Suppress("NewLineAtEndOfFile")
|
||||
fun TextView.setHtmlContent(value: String) {
|
||||
movementMethod = LinkMovementMethod.getInstance()
|
||||
text = HtmlCompat.fromHtml(value, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2016 Andy Scherzinger
|
||||
* Copyright (C) 2016 Nextcloud
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.databinding.CommunityLayoutBinding;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
|
||||
/**
|
||||
* Activity providing information about ways to participate in the app's development.
|
||||
*/
|
||||
public class CommunityActivity extends DrawerActivity {
|
||||
|
||||
protected CommunityLayoutBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = CommunityLayoutBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
// setup toolbar
|
||||
setupToolbar();
|
||||
|
||||
updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_community));
|
||||
|
||||
// setup drawer
|
||||
setupDrawer(R.id.nav_community);
|
||||
|
||||
setupContent();
|
||||
}
|
||||
|
||||
protected void setupContent() {
|
||||
binding.communityReleaseCandidateText.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
TextView contributeForumView = binding.communityContributeForumText;
|
||||
contributeForumView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
contributeForumView.setText(Html.fromHtml(getString(R.string.community_contribute_forum_text) + " " +
|
||||
getString(R.string.community_contribute_forum_text_link,
|
||||
viewThemeUtils
|
||||
.files
|
||||
.primaryColorToHexString(this),
|
||||
getString(R.string.help_link),
|
||||
getString(R.string.community_contribute_forum_forum))));
|
||||
|
||||
TextView contributeTranslationView = binding.communityContributeTranslateText;
|
||||
contributeTranslationView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
contributeTranslationView.setText(Html.fromHtml(
|
||||
getString(R.string.community_contribute_translate_link,
|
||||
viewThemeUtils.files.primaryColorToHexString(this),
|
||||
getString(R.string.translation_link),
|
||||
getString(R.string.community_contribute_translate_translate)) + " " +
|
||||
getString(R.string.community_contribute_translate_text)));
|
||||
|
||||
TextView contributeGithubView = binding.communityContributeGithubText;
|
||||
contributeGithubView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
contributeGithubView.setText(Html.fromHtml(
|
||||
getString(R.string.community_contribute_github_text,
|
||||
getString(R.string.community_contribute_github_text_link,
|
||||
viewThemeUtils.files.primaryColorToHexString(this),
|
||||
getString(R.string.contributing_link)))));
|
||||
|
||||
MaterialButton reportButton = binding.communityTestingReport;
|
||||
viewThemeUtils.material.colorMaterialButtonPrimaryFilled(reportButton);
|
||||
reportButton.setOnClickListener(v -> DisplayUtils.startLinkIntent(this, R.string.report_issue_empty_link));
|
||||
|
||||
binding.communityBetaFdroid.setOnClickListener(
|
||||
l -> DisplayUtils.startLinkIntent(this, R.string.fdroid_beta_link));
|
||||
|
||||
binding.communityReleaseCandidateFdroid.setOnClickListener(
|
||||
l -> DisplayUtils.startLinkIntent(this, R.string.fdroid_link));
|
||||
|
||||
binding.communityReleaseCandidatePlaystore.setOnClickListener(
|
||||
l -> DisplayUtils.startLinkIntent(this, R.string.play_store_register_beta));
|
||||
|
||||
binding.communityBetaApk.setOnClickListener(
|
||||
l -> DisplayUtils.startLinkIntent(this, R.string.beta_apk_link));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
boolean retval = true;
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
if (isDrawerOpen()) {
|
||||
closeDrawer();
|
||||
} else {
|
||||
openDrawer();
|
||||
}
|
||||
} else {
|
||||
retval = super.onOptionsItemSelected(item);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
setDrawerMenuItemChecked(R.id.nav_community);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2016 Andy Scherzinger
|
||||
* Copyright (C) 2016 Nextcloud
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.MenuItem
|
||||
import com.nextcloud.utils.extensions.setHtmlContent
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.databinding.CommunityLayoutBinding
|
||||
import com.owncloud.android.utils.DisplayUtils
|
||||
|
||||
/**
|
||||
* Activity providing information about ways to participate in the app's development.
|
||||
*/
|
||||
open class CommunityActivity : DrawerActivity() {
|
||||
lateinit var binding: CommunityLayoutBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = CommunityLayoutBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
setupToolbar()
|
||||
updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_community))
|
||||
|
||||
setupDrawer(R.id.nav_community)
|
||||
binding.communityReleaseCandidateText.movementMethod = LinkMovementMethod.getInstance()
|
||||
setupContributeForumView()
|
||||
setupContributeTranslationView()
|
||||
setupContributeGithubView()
|
||||
setupReportButton()
|
||||
setOnClickListeners()
|
||||
}
|
||||
|
||||
private fun setupContributeForumView() {
|
||||
val htmlContent = getString(R.string.community_contribute_forum_text) + " " +
|
||||
getString(
|
||||
R.string.community_contribute_forum_text_link,
|
||||
viewThemeUtils.files
|
||||
.primaryColorToHexString(this),
|
||||
getString(R.string.help_link),
|
||||
getString(R.string.community_contribute_forum_forum)
|
||||
)
|
||||
binding.communityContributeForumText.setHtmlContent(htmlContent)
|
||||
}
|
||||
|
||||
private fun setupContributeTranslationView() {
|
||||
val htmlContent = getString(
|
||||
R.string.community_contribute_translate_link,
|
||||
viewThemeUtils.files.primaryColorToHexString(this),
|
||||
getString(R.string.translation_link),
|
||||
getString(R.string.community_contribute_translate_translate)
|
||||
) + " " +
|
||||
getString(R.string.community_contribute_translate_text)
|
||||
binding.communityContributeTranslateText.setHtmlContent(htmlContent)
|
||||
}
|
||||
|
||||
private fun setupContributeGithubView() {
|
||||
val htmlContent = getString(
|
||||
R.string.community_contribute_github_text,
|
||||
getString(
|
||||
R.string.community_contribute_github_text_link,
|
||||
viewThemeUtils.files.primaryColorToHexString(this),
|
||||
getString(R.string.contributing_link)
|
||||
)
|
||||
)
|
||||
binding.communityContributeGithubText.setHtmlContent(htmlContent)
|
||||
}
|
||||
|
||||
private fun setupReportButton() {
|
||||
val reportButton = binding.communityTestingReport
|
||||
viewThemeUtils.material.colorMaterialButtonPrimaryFilled(reportButton)
|
||||
reportButton.setOnClickListener {
|
||||
DisplayUtils.startLinkIntent(
|
||||
this,
|
||||
R.string.report_issue_empty_link
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setOnClickListeners() {
|
||||
binding.communityBetaFdroid.setOnClickListener {
|
||||
DisplayUtils.startLinkIntent(
|
||||
this,
|
||||
R.string.fdroid_beta_link
|
||||
)
|
||||
}
|
||||
binding.communityReleaseCandidateFdroid.setOnClickListener {
|
||||
DisplayUtils.startLinkIntent(
|
||||
this,
|
||||
R.string.fdroid_link
|
||||
)
|
||||
}
|
||||
binding.communityReleaseCandidatePlaystore.setOnClickListener {
|
||||
DisplayUtils.startLinkIntent(
|
||||
this,
|
||||
R.string.play_store_register_beta
|
||||
)
|
||||
}
|
||||
binding.communityBetaApk.setOnClickListener {
|
||||
DisplayUtils.startLinkIntent(
|
||||
this,
|
||||
R.string.beta_apk_link
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
var retval = true
|
||||
if (item.itemId == android.R.id.home) {
|
||||
if (isDrawerOpen) {
|
||||
closeDrawer()
|
||||
} else {
|
||||
openDrawer()
|
||||
}
|
||||
} else {
|
||||
retval = super.onOptionsItemSelected(item)
|
||||
}
|
||||
return retval
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setDrawerMenuItemChecked(R.id.nav_community)
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import com.owncloud.android.ui.fragment.contactsbackup.BackupListFragment;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
@ -115,6 +116,8 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
|
|||
}
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,12 +140,14 @@ public class ContactsPreferenceActivity extends FileActivity implements FileFrag
|
|||
// not needed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (getSupportFragmentManager().findFragmentByTag(BackupListFragment.TAG) != null) {
|
||||
getSupportFragmentManager().popBackStack(BACKUP_TO_LIST, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
} else {
|
||||
finish();
|
||||
private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
if (getSupportFragmentManager().findFragmentByTag(BackupListFragment.TAG) != null) {
|
||||
getSupportFragmentManager().popBackStack(BACKUP_TO_LIST, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2507,8 +2507,7 @@ public class FileDisplayActivity extends FileActivity
|
|||
setUser(user);
|
||||
|
||||
if (fileId == null) {
|
||||
dismissLoadingDialog();
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.error_retrieving_file));
|
||||
onFileRequestError(null);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2529,8 +2528,7 @@ public class FileDisplayActivity extends FileActivity
|
|||
setUser(user);
|
||||
|
||||
if (filepath == null) {
|
||||
dismissLoadingDialog();
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.error_retrieving_file));
|
||||
onFileRequestError(null);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2544,8 +2542,7 @@ public class FileDisplayActivity extends FileActivity
|
|||
try {
|
||||
client = clientFactory.create(user);
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
dismissLoadingDialog();
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.error_retrieving_file));
|
||||
onFileRequestError(null);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2554,9 +2551,17 @@ public class FileDisplayActivity extends FileActivity
|
|||
client,
|
||||
storageManager,
|
||||
user);
|
||||
asyncRunner.postQuickTask(getRemoteFileTask, this::onFileRequestResult, null);
|
||||
asyncRunner.postQuickTask(getRemoteFileTask, this::onFileRequestResult, this::onFileRequestError);
|
||||
}
|
||||
|
||||
private Unit onFileRequestError(Throwable throwable) {
|
||||
dismissLoadingDialog();
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.error_retrieving_file));
|
||||
Log_OC.e(TAG, "Requesting file from remote failed!", throwable);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private Unit onFileRequestResult(GetRemoteFileTask.Result result) {
|
||||
dismissLoadingDialog();
|
||||
|
||||
|
|
|
@ -18,40 +18,29 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.activity
|
||||
|
||||
package com.owncloud.android.ui.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.ui.fragment.OCFileListFragment;
|
||||
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import android.os.Bundle
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.ui.fragment.OCFileListFragment
|
||||
|
||||
/**
|
||||
* File picker of remote files
|
||||
*/
|
||||
public class FilePickerActivity extends FolderPickerActivity {
|
||||
class FilePickerActivity : FolderPickerActivity() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
super.onClick(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createFragments() {
|
||||
OCFileListFragment listOfFiles = new OCFileListFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean(OCFileListFragment.ARG_ONLY_FOLDERS_CLICKABLE, true);
|
||||
args.putBoolean(OCFileListFragment.ARG_HIDE_FAB, true);
|
||||
args.putBoolean(OCFileListFragment.ARG_HIDE_ITEM_OPTIONS, true);
|
||||
args.putBoolean(OCFileListFragment.ARG_SEARCH_ONLY_FOLDER, false);
|
||||
args.putBoolean(OCFileListFragment.ARG_FILE_SELECTABLE, true);
|
||||
args.putString(OCFileListFragment.ARG_MIMETYPE, getIntent().getStringExtra(OCFileListFragment.ARG_MIMETYPE));
|
||||
listOfFiles.setArguments(args);
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||
transaction.add(R.id.fragment_container, listOfFiles, TAG_LIST_OF_FOLDERS);
|
||||
transaction.commit();
|
||||
override fun createFragments() {
|
||||
val listOfFiles = OCFileListFragment()
|
||||
val args = Bundle()
|
||||
args.putBoolean(OCFileListFragment.ARG_ONLY_FOLDERS_CLICKABLE, true)
|
||||
args.putBoolean(OCFileListFragment.ARG_HIDE_FAB, true)
|
||||
args.putBoolean(OCFileListFragment.ARG_HIDE_ITEM_OPTIONS, true)
|
||||
args.putBoolean(OCFileListFragment.ARG_SEARCH_ONLY_FOLDER, false)
|
||||
args.putBoolean(OCFileListFragment.ARG_FILE_SELECTABLE, true)
|
||||
args.putString(OCFileListFragment.ARG_MIMETYPE, intent.getStringExtra(OCFileListFragment.ARG_MIMETYPE))
|
||||
listOfFiles.arguments = args
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
transaction.add(R.id.fragment_container, listOfFiles, TAG_LIST_OF_FOLDERS)
|
||||
transaction.commit()
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ import android.view.ActionMode
|
|||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.nextcloud.client.di.Injectable
|
||||
|
@ -125,9 +126,33 @@ open class FolderPickerActivity :
|
|||
|
||||
// sets message for empty list of folders
|
||||
setBackgroundText()
|
||||
|
||||
handleOnBackPressed()
|
||||
|
||||
Log_OC.d(TAG, "onCreate() end")
|
||||
}
|
||||
|
||||
private fun handleOnBackPressed() {
|
||||
onBackPressedDispatcher.addCallback(
|
||||
this,
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
val listOfFiles = listOfFilesFragment
|
||||
if (listOfFiles != null) {
|
||||
// should never be null, indeed
|
||||
val levelsUp = listOfFiles.onBrowseUp()
|
||||
if (levelsUp == 0) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
file = listOfFiles.currentFile
|
||||
updateUiElements()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onActionModeStarted(mode: ActionMode) {
|
||||
super.onActionModeStarted(mode)
|
||||
if (account != null) {
|
||||
|
@ -321,20 +346,6 @@ open class FolderPickerActivity :
|
|||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
val listOfFiles = listOfFilesFragment
|
||||
if (listOfFiles != null) {
|
||||
// should never be null, indeed
|
||||
val levelsUp = listOfFiles.onBrowseUp()
|
||||
if (levelsUp == 0) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
file = listOfFiles.currentFile
|
||||
updateUiElements()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateUiElements() {
|
||||
toggleChooseEnabled()
|
||||
updateNavigationElementsInActionBar()
|
||||
|
@ -605,6 +616,7 @@ open class FolderPickerActivity :
|
|||
const val MOVE_OR_COPY = "MOVE_OR_COPY"
|
||||
const val CHOOSE_LOCATION = "CHOOSE_LOCATION"
|
||||
private val TAG = FolderPickerActivity::class.java.simpleName
|
||||
protected const val TAG_LIST_OF_FOLDERS = "LIST_OF_FOLDERS"
|
||||
|
||||
const val TAG_LIST_OF_FOLDERS = "LIST_OF_FOLDERS"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,373 +0,0 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author Mario Danic
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2017 Andy Scherzinger
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
* Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.nextcloud.client.account.User;
|
||||
import com.nextcloud.client.account.UserAccountManager;
|
||||
import com.nextcloud.client.jobs.NotificationWork;
|
||||
import com.nextcloud.client.network.ClientFactory;
|
||||
import com.nextcloud.java.util.Optional;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.databinding.NotificationsLayoutBinding;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.notifications.GetNotificationsRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.notifications.models.Notification;
|
||||
import com.owncloud.android.ui.adapter.NotificationListAdapter;
|
||||
import com.owncloud.android.ui.asynctasks.DeleteAllNotificationsTask;
|
||||
import com.owncloud.android.ui.notifications.NotificationsContract;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.PushUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
/**
|
||||
* Activity displaying all server side stored notification items.
|
||||
*/
|
||||
public class NotificationsActivity extends DrawerActivity implements NotificationsContract.View {
|
||||
|
||||
private static final String TAG = NotificationsActivity.class.getSimpleName();
|
||||
|
||||
private NotificationsLayoutBinding binding;
|
||||
private NotificationListAdapter adapter;
|
||||
private Snackbar snackbar;
|
||||
private OwnCloudClient client;
|
||||
private Optional<User> optionalUser;
|
||||
|
||||
@Inject ClientFactory clientFactory;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log_OC.v(TAG, "onCreate() start");
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = NotificationsLayoutBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
optionalUser = getUser();
|
||||
|
||||
// use account from intent (opened via android notification can have a different account than current one)
|
||||
if (getIntent() != null && getIntent().getExtras() != null) {
|
||||
String accountName = getIntent().getExtras().getString(NotificationWork.KEY_NOTIFICATION_ACCOUNT);
|
||||
if (accountName != null && optionalUser.isPresent()) {
|
||||
User user = optionalUser.get();
|
||||
if (user.getAccountName().equalsIgnoreCase(accountName)) {
|
||||
accountManager.setCurrentOwnCloudAccount(accountName);
|
||||
setUser(getUserAccountManager().getUser());
|
||||
optionalUser = getUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup toolbar
|
||||
setupToolbar();
|
||||
|
||||
updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_item_notifications));
|
||||
|
||||
viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList);
|
||||
viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingEmpty);
|
||||
|
||||
// setup drawer
|
||||
setupDrawer(R.id.nav_notifications);
|
||||
|
||||
if (!optionalUser.isPresent()) {
|
||||
// show error
|
||||
runOnUiThread(() -> setEmptyContent(
|
||||
getString(R.string.notifications_no_results_headline),
|
||||
getString(R.string.account_not_found))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
binding.swipeContainingList.setOnRefreshListener(() -> {
|
||||
setLoadingMessage();
|
||||
binding.swipeContainingList.setRefreshing(true);
|
||||
fetchAndSetData();
|
||||
});
|
||||
|
||||
binding.swipeContainingEmpty.setOnRefreshListener(() -> {
|
||||
setLoadingMessageEmpty();
|
||||
fetchAndSetData();
|
||||
});
|
||||
|
||||
setupPushWarning();
|
||||
setupContent();
|
||||
}
|
||||
|
||||
private void setupPushWarning() {
|
||||
if (!getResources().getBoolean(R.bool.show_push_warning)) {
|
||||
return;
|
||||
}
|
||||
if (snackbar != null) {
|
||||
if (!snackbar.isShown()) {
|
||||
snackbar.show();
|
||||
}
|
||||
} else {
|
||||
String pushUrl = getResources().getString(R.string.push_server_url);
|
||||
|
||||
if (pushUrl.isEmpty()) {
|
||||
snackbar = Snackbar.make(binding.emptyList.emptyListView,
|
||||
R.string.push_notifications_not_implemented,
|
||||
Snackbar.LENGTH_INDEFINITE);
|
||||
} else {
|
||||
final ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(this);
|
||||
final String accountName = optionalUser.isPresent() ? optionalUser.get().getAccountName() : "";
|
||||
final boolean usesOldLogin = arbitraryDataProvider.getBooleanValue(accountName,
|
||||
UserAccountManager.ACCOUNT_USES_STANDARD_PASSWORD);
|
||||
|
||||
if (usesOldLogin) {
|
||||
snackbar = Snackbar.make(binding.emptyList.emptyListView,
|
||||
R.string.push_notifications_old_login,
|
||||
Snackbar.LENGTH_INDEFINITE);
|
||||
} else {
|
||||
String pushValue = arbitraryDataProvider.getValue(accountName, PushUtils.KEY_PUSH);
|
||||
|
||||
if (pushValue == null || pushValue.isEmpty()) {
|
||||
snackbar = Snackbar.make(binding.emptyList.emptyListView,
|
||||
R.string.push_notifications_temp_error,
|
||||
Snackbar.LENGTH_INDEFINITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (snackbar != null && !snackbar.isShown()) {
|
||||
snackbar.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openDrawer() {
|
||||
super.openDrawer();
|
||||
|
||||
if (snackbar != null && snackbar.isShown()) {
|
||||
snackbar.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeDrawer() {
|
||||
super.closeDrawer();
|
||||
|
||||
setupPushWarning();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets up the UI elements and loads all notification items.
|
||||
*/
|
||||
private void setupContent() {
|
||||
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_notification);
|
||||
setLoadingMessageEmpty();
|
||||
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
||||
|
||||
binding.list.setLayoutManager(layoutManager);
|
||||
|
||||
fetchAndSetData();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void populateList(List<Notification> notifications) {
|
||||
initializeAdapter();
|
||||
adapter.setNotificationItems(notifications);
|
||||
binding.loadingContent.setVisibility(View.GONE);
|
||||
|
||||
if (notifications.size() > 0) {
|
||||
binding.swipeContainingEmpty.setVisibility(View.GONE);
|
||||
binding.swipeContainingList.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
setEmptyContent(
|
||||
getString(R.string.notifications_no_results_headline),
|
||||
getString(R.string.notifications_no_results_message)
|
||||
);
|
||||
binding.swipeContainingList.setVisibility(View.GONE);
|
||||
binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchAndSetData() {
|
||||
Thread t = new Thread(() -> {
|
||||
initializeAdapter();
|
||||
|
||||
GetNotificationsRemoteOperation getRemoteNotificationOperation = new GetNotificationsRemoteOperation();
|
||||
final RemoteOperationResult<List<Notification>> result = getRemoteNotificationOperation.execute(client);
|
||||
|
||||
if (result.isSuccess() && result.getResultData() != null) {
|
||||
runOnUiThread(() -> populateList(result.getResultData()));
|
||||
} else {
|
||||
Log_OC.d(TAG, result.getLogMessage());
|
||||
// show error
|
||||
runOnUiThread(() -> setEmptyContent(getString(R.string.notifications_no_results_headline), result.getLogMessage()));
|
||||
}
|
||||
|
||||
hideRefreshLayoutLoader();
|
||||
});
|
||||
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void initializeClient() {
|
||||
if (client == null && optionalUser.isPresent()) {
|
||||
try {
|
||||
User user = optionalUser.get();
|
||||
client = clientFactory.create(user);
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
Log_OC.e(TAG, "Error initializing client", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeAdapter() {
|
||||
initializeClient();
|
||||
if (adapter == null) {
|
||||
adapter = new NotificationListAdapter(client, this, viewThemeUtils);
|
||||
binding.list.setAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideRefreshLayoutLoader() {
|
||||
runOnUiThread(() -> {
|
||||
binding.swipeContainingList.setRefreshing(false);
|
||||
binding.swipeContainingEmpty.setRefreshing(false);
|
||||
});
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.activity_notifications, menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
boolean retval = true;
|
||||
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
if (isDrawerOpen()) {
|
||||
closeDrawer();
|
||||
} else {
|
||||
openDrawer();
|
||||
}
|
||||
} else if (itemId == R.id.action_empty_notifications) {
|
||||
new DeleteAllNotificationsTask(client, this).execute();
|
||||
} else {
|
||||
retval = super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
private void setLoadingMessage() {
|
||||
binding.swipeContainingEmpty.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setLoadingMessageEmpty() {
|
||||
binding.swipeContainingList.setVisibility(View.GONE);
|
||||
binding.emptyList.emptyListView.setVisibility(View.GONE);
|
||||
binding.loadingContent.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setEmptyContent(String headline, String message) {
|
||||
binding.swipeContainingList.setVisibility(View.GONE);
|
||||
binding.loadingContent.setVisibility(View.GONE);
|
||||
binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
|
||||
binding.emptyList.emptyListView.setVisibility(View.VISIBLE);
|
||||
|
||||
binding.emptyList.emptyListViewHeadline.setText(headline);
|
||||
binding.emptyList.emptyListViewText.setText(message);
|
||||
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_notification);
|
||||
|
||||
binding.emptyList.emptyListViewText.setVisibility(View.VISIBLE);
|
||||
binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
setDrawerMenuItemChecked(R.id.nav_notifications);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemovedNotification(boolean isSuccess) {
|
||||
if (!isSuccess) {
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.remove_notification_failed));
|
||||
fetchAndSetData();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotification(NotificationListAdapter.NotificationViewHolder holder) {
|
||||
adapter.removeNotification(holder);
|
||||
|
||||
if (adapter.getItemCount() == 0) {
|
||||
setEmptyContent(getString(R.string.notifications_no_results_headline), getString(R.string.notifications_no_results_message));
|
||||
binding.swipeContainingList.setVisibility(View.GONE);
|
||||
binding.loadingContent.setVisibility(View.GONE);
|
||||
binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemovedAllNotifications(boolean isSuccess) {
|
||||
if (isSuccess) {
|
||||
adapter.removeAllNotifications();
|
||||
setEmptyContent(getString(R.string.notifications_no_results_headline), getString(R.string.notifications_no_results_message));
|
||||
binding.loadingContent.setVisibility(View.GONE);
|
||||
binding.swipeContainingList.setVisibility(View.GONE);
|
||||
binding.swipeContainingEmpty.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.clear_notifications_failed));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionCallback(boolean isSuccess,
|
||||
Notification notification,
|
||||
NotificationListAdapter.NotificationViewHolder holder) {
|
||||
if (isSuccess) {
|
||||
adapter.removeNotification(holder);
|
||||
} else {
|
||||
adapter.setButtons(holder, notification);
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.notification_action_failed));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,376 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author Mario Danic
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2017 Andy Scherzinger
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
* Copyright (C) 2020 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.nextcloud.client.account.User
|
||||
import com.nextcloud.client.account.UserAccountManager
|
||||
import com.nextcloud.client.jobs.NotificationWork
|
||||
import com.nextcloud.client.network.ClientFactory.CreationException
|
||||
import com.nextcloud.java.util.Optional
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.databinding.NotificationsLayoutBinding
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl
|
||||
import com.owncloud.android.lib.common.OwnCloudClient
|
||||
import com.owncloud.android.lib.common.utils.Log_OC
|
||||
import com.owncloud.android.lib.resources.notifications.GetNotificationsRemoteOperation
|
||||
import com.owncloud.android.lib.resources.notifications.models.Notification
|
||||
import com.owncloud.android.ui.adapter.NotificationListAdapter
|
||||
import com.owncloud.android.ui.adapter.NotificationListAdapter.NotificationViewHolder
|
||||
import com.owncloud.android.ui.asynctasks.DeleteAllNotificationsTask
|
||||
import com.owncloud.android.ui.notifications.NotificationsContract
|
||||
import com.owncloud.android.utils.DisplayUtils
|
||||
import com.owncloud.android.utils.PushUtils
|
||||
|
||||
/**
|
||||
* Activity displaying all server side stored notification items.
|
||||
*/
|
||||
class NotificationsActivity : DrawerActivity(), NotificationsContract.View {
|
||||
|
||||
private lateinit var binding: NotificationsLayoutBinding
|
||||
|
||||
private var adapter: NotificationListAdapter? = null
|
||||
private var snackbar: Snackbar? = null
|
||||
private var client: OwnCloudClient? = null
|
||||
private var optionalUser: Optional<User>? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
Log_OC.v(TAG, "onCreate() start")
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = NotificationsLayoutBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
optionalUser = user
|
||||
|
||||
intent?.let {
|
||||
it.extras?.let { bundle ->
|
||||
setupUser(bundle)
|
||||
}
|
||||
}
|
||||
|
||||
setupToolbar()
|
||||
updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_item_notifications))
|
||||
setupDrawer(R.id.nav_notifications)
|
||||
|
||||
if (optionalUser?.isPresent == false) {
|
||||
showError()
|
||||
}
|
||||
|
||||
setupContainingList()
|
||||
setupPushWarning()
|
||||
setupContent()
|
||||
}
|
||||
|
||||
private fun setupContainingList() {
|
||||
viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList)
|
||||
viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingEmpty)
|
||||
binding.swipeContainingList.setOnRefreshListener {
|
||||
setLoadingMessage()
|
||||
binding.swipeContainingList.isRefreshing = true
|
||||
fetchAndSetData()
|
||||
}
|
||||
binding.swipeContainingEmpty.setOnRefreshListener {
|
||||
setLoadingMessageEmpty()
|
||||
fetchAndSetData()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupUser(bundle: Bundle) {
|
||||
val accountName = bundle.getString(NotificationWork.KEY_NOTIFICATION_ACCOUNT)
|
||||
|
||||
if (accountName != null && optionalUser?.isPresent == true) {
|
||||
val user = optionalUser?.get()
|
||||
if (user?.accountName.equals(accountName, ignoreCase = true)) {
|
||||
accountManager.setCurrentOwnCloudAccount(accountName)
|
||||
setUser(userAccountManager.user)
|
||||
optionalUser = getUser()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showError() {
|
||||
runOnUiThread {
|
||||
setEmptyContent(
|
||||
getString(R.string.notifications_no_results_headline),
|
||||
getString(R.string.account_not_found)
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
private fun setupPushWarning() {
|
||||
if (!resources.getBoolean(R.bool.show_push_warning)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (snackbar != null) {
|
||||
if (snackbar?.isShown == false) {
|
||||
snackbar?.show()
|
||||
}
|
||||
} else {
|
||||
val pushUrl = resources.getString(R.string.push_server_url)
|
||||
if (pushUrl.isEmpty()) {
|
||||
snackbar = Snackbar.make(
|
||||
binding.emptyList.emptyListView,
|
||||
R.string.push_notifications_not_implemented,
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
)
|
||||
} else {
|
||||
val arbitraryDataProvider: ArbitraryDataProvider = ArbitraryDataProviderImpl(this)
|
||||
val accountName: String = if (optionalUser?.isPresent == true) {
|
||||
optionalUser?.get()?.accountName ?: ""
|
||||
} else {
|
||||
""
|
||||
}
|
||||
val usesOldLogin = arbitraryDataProvider.getBooleanValue(
|
||||
accountName,
|
||||
UserAccountManager.ACCOUNT_USES_STANDARD_PASSWORD
|
||||
)
|
||||
|
||||
if (usesOldLogin) {
|
||||
snackbar = Snackbar.make(
|
||||
binding.emptyList.emptyListView,
|
||||
R.string.push_notifications_old_login,
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
)
|
||||
} else {
|
||||
val pushValue = arbitraryDataProvider.getValue(accountName, PushUtils.KEY_PUSH)
|
||||
if (pushValue.isEmpty()) {
|
||||
snackbar = Snackbar.make(
|
||||
binding.emptyList.emptyListView,
|
||||
R.string.push_notifications_temp_error,
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (snackbar != null && snackbar?.isShown == false) {
|
||||
snackbar?.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun openDrawer() {
|
||||
super.openDrawer()
|
||||
if (snackbar != null && snackbar?.isShown == true) {
|
||||
snackbar?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun closeDrawer() {
|
||||
super.closeDrawer()
|
||||
setupPushWarning()
|
||||
}
|
||||
|
||||
/**
|
||||
* sets up the UI elements and loads all notification items.
|
||||
*/
|
||||
private fun setupContent() {
|
||||
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_notification)
|
||||
setLoadingMessageEmpty()
|
||||
val layoutManager = LinearLayoutManager(this)
|
||||
binding.list.layoutManager = layoutManager
|
||||
fetchAndSetData()
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun populateList(notifications: List<Notification>?) {
|
||||
initializeAdapter()
|
||||
adapter?.setNotificationItems(notifications)
|
||||
binding.loadingContent.visibility = View.GONE
|
||||
|
||||
if (notifications?.isNotEmpty() == true) {
|
||||
binding.swipeContainingEmpty.visibility = View.GONE
|
||||
binding.swipeContainingList.visibility = View.VISIBLE
|
||||
} else {
|
||||
setEmptyContent(
|
||||
getString(R.string.notifications_no_results_headline),
|
||||
getString(R.string.notifications_no_results_message)
|
||||
)
|
||||
binding.swipeContainingList.visibility = View.GONE
|
||||
binding.swipeContainingEmpty.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchAndSetData() {
|
||||
val t = Thread {
|
||||
initializeAdapter()
|
||||
val getRemoteNotificationOperation = GetNotificationsRemoteOperation()
|
||||
val result = getRemoteNotificationOperation.execute(client)
|
||||
if (result.isSuccess && result.resultData != null) {
|
||||
runOnUiThread { populateList(result.resultData) }
|
||||
} else {
|
||||
Log_OC.d(TAG, result.logMessage)
|
||||
// show error
|
||||
runOnUiThread {
|
||||
setEmptyContent(
|
||||
getString(R.string.notifications_no_results_headline),
|
||||
result.logMessage
|
||||
)
|
||||
}
|
||||
}
|
||||
hideRefreshLayoutLoader()
|
||||
}
|
||||
t.start()
|
||||
}
|
||||
|
||||
private fun initializeClient() {
|
||||
if (client == null && optionalUser?.isPresent == true) {
|
||||
try {
|
||||
val user = optionalUser?.get()
|
||||
client = clientFactory.create(user)
|
||||
} catch (e: CreationException) {
|
||||
Log_OC.e(TAG, "Error initializing client", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeAdapter() {
|
||||
initializeClient()
|
||||
if (adapter == null) {
|
||||
adapter = NotificationListAdapter(client, this, viewThemeUtils)
|
||||
binding.list.adapter = adapter
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideRefreshLayoutLoader() {
|
||||
runOnUiThread {
|
||||
binding.swipeContainingList.isRefreshing = false
|
||||
binding.swipeContainingEmpty.isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.activity_notifications, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
var retval = true
|
||||
val itemId = item.itemId
|
||||
if (itemId == android.R.id.home) {
|
||||
if (isDrawerOpen) {
|
||||
closeDrawer()
|
||||
} else {
|
||||
openDrawer()
|
||||
}
|
||||
} else if (itemId == R.id.action_empty_notifications) {
|
||||
DeleteAllNotificationsTask(client, this).execute()
|
||||
} else {
|
||||
retval = super.onOptionsItemSelected(item)
|
||||
}
|
||||
return retval
|
||||
}
|
||||
|
||||
private fun setLoadingMessage() {
|
||||
binding.swipeContainingEmpty.visibility = View.GONE
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun setLoadingMessageEmpty() {
|
||||
binding.swipeContainingList.visibility = View.GONE
|
||||
binding.emptyList.emptyListView.visibility = View.GONE
|
||||
binding.loadingContent.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun setEmptyContent(headline: String?, message: String?) {
|
||||
binding.swipeContainingList.visibility = View.GONE
|
||||
binding.loadingContent.visibility = View.GONE
|
||||
binding.swipeContainingEmpty.visibility = View.VISIBLE
|
||||
binding.emptyList.emptyListView.visibility = View.VISIBLE
|
||||
binding.emptyList.emptyListViewHeadline.text = headline
|
||||
binding.emptyList.emptyListViewText.text = message
|
||||
binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_notification)
|
||||
binding.emptyList.emptyListViewText.visibility = View.VISIBLE
|
||||
binding.emptyList.emptyListIcon.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setDrawerMenuItemChecked(R.id.nav_notifications)
|
||||
}
|
||||
|
||||
override fun onRemovedNotification(isSuccess: Boolean) {
|
||||
if (!isSuccess) {
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.remove_notification_failed))
|
||||
fetchAndSetData()
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeNotification(holder: NotificationViewHolder) {
|
||||
adapter?.removeNotification(holder)
|
||||
if (adapter?.itemCount == 0) {
|
||||
setEmptyContent(
|
||||
getString(R.string.notifications_no_results_headline),
|
||||
getString(R.string.notifications_no_results_message)
|
||||
)
|
||||
binding.swipeContainingList.visibility = View.GONE
|
||||
binding.loadingContent.visibility = View.GONE
|
||||
binding.swipeContainingEmpty.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRemovedAllNotifications(isSuccess: Boolean) {
|
||||
if (isSuccess) {
|
||||
adapter?.removeAllNotifications()
|
||||
setEmptyContent(
|
||||
getString(R.string.notifications_no_results_headline),
|
||||
getString(R.string.notifications_no_results_message)
|
||||
)
|
||||
binding.loadingContent.visibility = View.GONE
|
||||
binding.swipeContainingList.visibility = View.GONE
|
||||
binding.swipeContainingEmpty.visibility = View.VISIBLE
|
||||
} else {
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.clear_notifications_failed))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActionCallback(
|
||||
isSuccess: Boolean,
|
||||
notification: Notification,
|
||||
holder: NotificationViewHolder
|
||||
) {
|
||||
if (isSuccess) {
|
||||
adapter?.removeNotification(holder)
|
||||
} else {
|
||||
adapter?.setButtons(holder, notification)
|
||||
DisplayUtils.showSnackMessage(this, getString(R.string.notification_action_failed))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = NotificationsActivity::class.java.simpleName
|
||||
}
|
||||
}
|
|
@ -61,6 +61,7 @@ import java.util.List;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
|
@ -258,6 +259,8 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
|
|||
|
||||
checkWritableFolder(mCurrentDir);
|
||||
|
||||
getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback);
|
||||
|
||||
Log_OC.d(TAG, "onCreate() end");
|
||||
}
|
||||
|
||||
|
@ -369,43 +372,45 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (isSearchOpen() && mSearchView != null) {
|
||||
mSearchView.setQuery("", false);
|
||||
mFileListFragment.onClose();
|
||||
mSearchView.onActionViewCollapsed();
|
||||
setDrawerIndicatorEnabled(isDrawerIndicatorAvailable());
|
||||
} else {
|
||||
if (mDirectories.getCount() <= SINGLE_DIR) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
if (isSearchOpen() && mSearchView != null) {
|
||||
mSearchView.setQuery("", false);
|
||||
mFileListFragment.onClose();
|
||||
mSearchView.onActionViewCollapsed();
|
||||
setDrawerIndicatorEnabled(isDrawerIndicatorAvailable());
|
||||
} else {
|
||||
if (mDirectories.getCount() <= SINGLE_DIR) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
File parentFolder = mCurrentDir.getParentFile();
|
||||
if (!parentFolder.canRead()) {
|
||||
checkLocalStoragePathPickerPermission();
|
||||
return;
|
||||
}
|
||||
File parentFolder = mCurrentDir.getParentFile();
|
||||
if (!parentFolder.canRead()) {
|
||||
checkLocalStoragePathPickerPermission();
|
||||
return;
|
||||
}
|
||||
|
||||
popDirname();
|
||||
mFileListFragment.onNavigateUp();
|
||||
mCurrentDir = mFileListFragment.getCurrentDirectory();
|
||||
checkWritableFolder(mCurrentDir);
|
||||
popDirname();
|
||||
mFileListFragment.onNavigateUp();
|
||||
mCurrentDir = mFileListFragment.getCurrentDirectory();
|
||||
checkWritableFolder(mCurrentDir);
|
||||
|
||||
if (mCurrentDir.getParentFile() == null) {
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||
if (mCurrentDir.getParentFile() == null) {
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
// invalidate checked state when navigating directories
|
||||
if (!mLocalFolderPickerMode) {
|
||||
setSelectAllMenuItem(mOptionsMenu.findItem(R.id.action_select_all), false);
|
||||
}
|
||||
}
|
||||
|
||||
// invalidate checked state when navigating directories
|
||||
if (!mLocalFolderPickerMode) {
|
||||
setSelectAllMenuItem(mOptionsMenu.findItem(R.id.action_select_all), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
|
|
|
@ -62,6 +62,8 @@ import com.owncloud.android.lib.common.utils.Log_OC;
|
|||
import com.owncloud.android.operations.RefreshFolderOperation;
|
||||
import com.owncloud.android.ui.activity.ConflictsResolveActivity;
|
||||
import com.owncloud.android.ui.activity.FileActivity;
|
||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||
import com.owncloud.android.ui.preview.PreviewImageFragment;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.MimeTypeUtil;
|
||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||
|
@ -346,12 +348,15 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
itemViewHolder.binding.uploadRightButton.setOnClickListener(v -> removeUpload(item));
|
||||
}
|
||||
itemViewHolder.binding.uploadRightButton.setVisibility(View.VISIBLE);
|
||||
} else { // UploadStatus.UPLOAD_SUCCESS
|
||||
} else { // UploadStatus.UPLOAD_SUCCEEDED
|
||||
itemViewHolder.binding.uploadRightButton.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
itemViewHolder.binding.uploadListItemLayout.setOnClickListener(null);
|
||||
|
||||
// Set icon or thumbnail
|
||||
itemViewHolder.binding.thumbnail.setImageResource(R.drawable.file);
|
||||
|
||||
// click on item
|
||||
if (item.getUploadStatus() == UploadStatus.UPLOAD_FAILED) {
|
||||
final UploadResult uploadResult = item.getLastResult();
|
||||
|
@ -381,12 +386,15 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
itemViewHolder.binding.uploadListItemLayout.setOnClickListener(v -> onUploadItemClick(item));
|
||||
} else if (item.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED){
|
||||
itemViewHolder.binding.uploadListItemLayout.setOnClickListener(v -> onUploadedItemClick(item));
|
||||
}
|
||||
|
||||
// Set icon or thumbnail
|
||||
itemViewHolder.binding.thumbnail.setImageResource(R.drawable.file);
|
||||
|
||||
// click on thumbnail to open locally
|
||||
if (item.getUploadStatus() != UploadStatus.UPLOAD_SUCCEEDED){
|
||||
itemViewHolder.binding.thumbnail.setOnClickListener(v -> onUploadingItemClick(item));
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancellation needs do be checked and done before changing the drawable in fileIcon, or
|
||||
|
@ -738,7 +746,10 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void onUploadItemClick(OCUpload file) {
|
||||
/**
|
||||
* Open local file.
|
||||
*/
|
||||
private void onUploadingItemClick(OCUpload file) {
|
||||
File f = new File(file.getLocalPath());
|
||||
if (!f.exists()) {
|
||||
DisplayUtils.showSnackMessage(parentActivity, R.string.local_file_not_found_message);
|
||||
|
@ -747,6 +758,30 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open remote file.
|
||||
*/
|
||||
private void onUploadedItemClick(OCUpload upload) {
|
||||
final OCFile file = parentActivity.getStorageManager().getFileByEncryptedRemotePath(upload.getRemotePath());
|
||||
if (file == null){
|
||||
DisplayUtils.showSnackMessage(parentActivity, R.string.error_retrieving_file);
|
||||
Log_OC.i(TAG, "Could not find uploaded file on remote.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (PreviewImageFragment.canBePreviewed(file)){
|
||||
//show image preview and stay in uploads tab
|
||||
Intent intent = FileDisplayActivity.openFileIntent(parentActivity, parentActivity.getUser().get(), file);
|
||||
parentActivity.startActivity(intent);
|
||||
}else{
|
||||
Intent intent = new Intent(parentActivity, FileDisplayActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra(FileDisplayActivity.KEY_FILE_PATH, upload.getRemotePath());
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
parentActivity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open file with app associates with its MIME type. If MIME type unknown, show list with all apps.
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">حذف </string>
|
||||
<string name="file_detail_activity_error">خطأ في استرداد النشاطات للملف</string>
|
||||
<string name="file_details_no_content">حدث خطأ في تحميل التفاصيل</string>
|
||||
<string name="file_downloader_notification_title_prefix">تنزيل \u0020</string>
|
||||
<string name="file_icon">الملف</string>
|
||||
<string name="file_keep">حفظ</string>
|
||||
<string name="file_list_empty">قم برفع بعض المحتوى أو زامن مع أجهزتك</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">Smazat</string>
|
||||
<string name="file_detail_activity_error">Při načítání aktivit u souboru došlo k chybě</string>
|
||||
<string name="file_details_no_content">Nepodařilo se načíst podrobnosti.</string>
|
||||
<string name="file_downloader_notification_title_prefix">Stahování \u0020</string>
|
||||
<string name="file_icon">Soubor</string>
|
||||
<string name="file_keep">Ponechat</string>
|
||||
<string name="file_list_empty">Nahrajte nějaký obsah, nebo synchronizujte s vašimi zařízeními.</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">Slet</string>
|
||||
<string name="file_detail_activity_error">Fejl ved indlæsning af aktiviteter for fil</string>
|
||||
<string name="file_details_no_content">Fejl ved indlæsning af detaljer</string>
|
||||
<string name="file_downloader_notification_title_prefix">Downloader \u0020</string>
|
||||
<string name="file_icon">Fil</string>
|
||||
<string name="file_keep">Behold</string>
|
||||
<string name="file_list_empty">Upload indhold eller synkronisér med dine enheder.</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">Löschen</string>
|
||||
<string name="file_detail_activity_error">Fehler beim Abrufen der Aktivitäten für die Datei</string>
|
||||
<string name="file_details_no_content">Fehler beim Laden der Details</string>
|
||||
<string name="file_downloader_notification_title_prefix">Herunterladen \u0020</string>
|
||||
<string name="file_icon">Datei</string>
|
||||
<string name="file_keep">Behalten</string>
|
||||
<string name="file_list_empty">Laden Sie Inhalt hoch oder synchronisieren Sie mit Ihren Geräten.</string>
|
||||
|
|
|
@ -239,6 +239,7 @@
|
|||
<string name="folder_confirm_create">Crear</string>
|
||||
<string name="folder_list_empty_headline">No hay carpetas aquí</string>
|
||||
<string name="folder_picker_choose_button_text">Seleccionar</string>
|
||||
<string name="folder_picker_move_button_text">Mover</string>
|
||||
<string name="forbidden_permissions">No se te permite %s</string>
|
||||
<string name="forbidden_permissions_copy">para copiar este archivo</string>
|
||||
<string name="forbidden_permissions_create">para crear este archivo</string>
|
||||
|
|
|
@ -540,6 +540,7 @@
|
|||
<string name="wait_a_moment">Aguarda un momento…</string>
|
||||
<string name="wait_checking_credentials">Verificando credenciales almacenadas</string>
|
||||
<string name="wait_for_tmp_copy_from_private_storage">Copiando el archivo desde almacenamiento privado</string>
|
||||
<string name="webview_version_check_alert_dialog_positive_button_title">Actualizar</string>
|
||||
<string name="what_s_new_image">Imagen de qué es nuevo</string>
|
||||
<string name="whats_new_skip">Omitir</string>
|
||||
<string name="whats_new_title">Nuevo en %1$s</string>
|
||||
|
|
|
@ -525,6 +525,7 @@
|
|||
<string name="version_dev_download">Lae alla</string>
|
||||
<string name="wait_a_moment">Oota üks hetk…</string>
|
||||
<string name="wait_for_tmp_copy_from_private_storage">Faili kopeerimine privaatsest salvestusalast</string>
|
||||
<string name="webview_version_check_alert_dialog_positive_button_title">Uuenda</string>
|
||||
<string name="whats_new_skip">Jäta vahele</string>
|
||||
<string name="whats_your_status">Mis on su staatus?</string>
|
||||
<string name="write_email">Saada kiri</string>
|
||||
|
|
|
@ -393,6 +393,7 @@
|
|||
<string name="folder_list_empty_headline">Ez dago karpetarik hemen</string>
|
||||
<string name="folder_picker_choose_button_text">Aukeratu</string>
|
||||
<string name="folder_picker_choose_caption_text">Aukeratu helburuko karpeta</string>
|
||||
<string name="folder_picker_copy_button_text">Kopiatu</string>
|
||||
<string name="folder_picker_move_button_text">Mugitu</string>
|
||||
<string name="forbidden_permissions">Ez daukazu baimenik %s</string>
|
||||
<string name="forbidden_permissions_copy">fitxategi hau kopiatzeko</string>
|
||||
|
@ -943,6 +944,7 @@
|
|||
<string name="wait_a_moment">Itxaron momentu bat…</string>
|
||||
<string name="wait_checking_credentials">Gordetako nortasun-datuak konprobatzen</string>
|
||||
<string name="wait_for_tmp_copy_from_private_storage">Fitxategia biltegiratze pribatutik kopiatzen</string>
|
||||
<string name="webview_version_check_alert_dialog_positive_button_title">Eguneratu</string>
|
||||
<string name="what_s_new_image">Zer da irudi berria</string>
|
||||
<string name="whats_new_skip">Salto egin</string>
|
||||
<string name="whats_new_title">Berria %1$s-n</string>
|
||||
|
|
|
@ -393,6 +393,7 @@
|
|||
<string name="folder_list_empty_headline">هیچ پوشه ای اینجا وجود ندارد</string>
|
||||
<string name="folder_picker_choose_button_text">انتخاب کردن</string>
|
||||
<string name="folder_picker_choose_caption_text">پوشهٔ هدف را انتخاب کنید</string>
|
||||
<string name="folder_picker_copy_button_text">رونوشت</string>
|
||||
<string name="folder_picker_move_button_text">انتقال</string>
|
||||
<string name="forbidden_permissions">شما مجاز نیستید%s</string>
|
||||
<string name="forbidden_permissions_copy">کپی این فایل</string>
|
||||
|
@ -943,6 +944,7 @@
|
|||
<string name="wait_a_moment">یک لحظه صبر کنید...</string>
|
||||
<string name="wait_checking_credentials">بررسی اعتبارنامههای ذخیره شده</string>
|
||||
<string name="wait_for_tmp_copy_from_private_storage">کپی کردن فایل از حافظه خصوصی</string>
|
||||
<string name="webview_version_check_alert_dialog_positive_button_title">بهروز رسانی</string>
|
||||
<string name="what_s_new_image">چه تصویر جدیدی است</string>
|
||||
<string name="whats_new_skip">رد شدن</string>
|
||||
<string name="whats_new_title">جدید در %1$s</string>
|
||||
|
|
|
@ -381,6 +381,7 @@
|
|||
<string name="folder_list_empty_headline">Ei kansioita täällä</string>
|
||||
<string name="folder_picker_choose_button_text">Valitse</string>
|
||||
<string name="folder_picker_choose_caption_text">Valitse kohdekansio</string>
|
||||
<string name="folder_picker_copy_button_text">Kopioi</string>
|
||||
<string name="folder_picker_move_button_text">Siirrä</string>
|
||||
<string name="forbidden_permissions">Sinulla ei ole oikeutta %s</string>
|
||||
<string name="forbidden_permissions_copy">kopioida tämä tiedosto</string>
|
||||
|
@ -906,6 +907,7 @@ GNU yleinen lisenssi, versio 2</string>
|
|||
<string name="wait_a_moment">Odota hetki…</string>
|
||||
<string name="wait_checking_credentials">Tarkistetaan tallennettuja tilitietoja</string>
|
||||
<string name="wait_for_tmp_copy_from_private_storage">Kopioidaan tiedostoa yksityisestä tallennustilasta</string>
|
||||
<string name="webview_version_check_alert_dialog_positive_button_title">Päivitä</string>
|
||||
<string name="what_s_new_image">Mitä uutta -kuva</string>
|
||||
<string name="whats_new_skip">Ohita</string>
|
||||
<string name="whats_new_title">Uutta versiossa %1$s</string>
|
||||
|
|
|
@ -327,7 +327,6 @@ Attention, la suppression est irréversible.</string>
|
|||
<string name="file_delete">Supprimer</string>
|
||||
<string name="file_detail_activity_error">Erreur lors de la récupération de l’activité du fichier</string>
|
||||
<string name="file_details_no_content">Impossible de charger les détails</string>
|
||||
<string name="file_downloader_notification_title_prefix">Téléchargement de \u0020</string>
|
||||
<string name="file_icon">Fichier</string>
|
||||
<string name="file_keep">Conserver</string>
|
||||
<string name="file_list_empty">Déposez du contenu ou synchronisez vos appareils.</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">Eliminar</string>
|
||||
<string name="file_detail_activity_error">Produciuse un erro ao recuperar actividades para o ficheiro</string>
|
||||
<string name="file_details_no_content">Produciuse un fallo ao cargar os detalles</string>
|
||||
<string name="file_downloader_notification_title_prefix">Descargando \u0020</string>
|
||||
<string name="file_icon">Ficheiro</string>
|
||||
<string name="file_keep">Conservar</string>
|
||||
<string name="file_list_empty">Envíe algún contido ou sincronice cos seus dispositivos.</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">Törlés</string>
|
||||
<string name="file_detail_activity_error">Hiba a fájl tevékenységeinek lekérésekor</string>
|
||||
<string name="file_details_no_content">A részletek betöltése sikertelen</string>
|
||||
<string name="file_downloader_notification_title_prefix">Letöltés \u0020</string>
|
||||
<string name="file_icon">Fájl</string>
|
||||
<string name="file_keep">Megtartás</string>
|
||||
<string name="file_list_empty">Töltsön fel új tartalmat vagy szinkronizáljon az eszközeivel</string>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<string name="actionbar_copy">Kopier</string>
|
||||
<string name="actionbar_mkdir">Ny mappe</string>
|
||||
<string name="actionbar_move">Flytt</string>
|
||||
<string name="actionbar_move_or_copy">Flytt eller kopier</string>
|
||||
<string name="actionbar_open_with">Åpne med</string>
|
||||
<string name="actionbar_search">Søk</string>
|
||||
<string name="actionbar_see_details">Detaljer</string>
|
||||
|
@ -425,6 +426,13 @@
|
|||
<string name="image_editor_rotate_ccw">Roter mot klokken</string>
|
||||
<string name="image_editor_rotate_cw">Roter med klokken</string>
|
||||
<string name="image_editor_unable_to_edit_image">Kan ikke endre bildet.</string>
|
||||
<string name="image_preview_filedetails">Fildetaljer</string>
|
||||
<string name="image_preview_image_taking_conditions">Betingelser for å ta bilder</string>
|
||||
<string name="image_preview_unit_fnumber">ƒ/%s</string>
|
||||
<string name="image_preview_unit_iso">ISO %s</string>
|
||||
<string name="image_preview_unit_megapixel">%s MP</string>
|
||||
<string name="image_preview_unit_millimetres">%s mm</string>
|
||||
<string name="image_preview_unit_seconds">%s s</string>
|
||||
<string name="in_folder">i mappen %1$s</string>
|
||||
<string name="instant_upload_existing">Last også opp eksisterende filer</string>
|
||||
<string name="instant_upload_on_charging">Bare last opp under lading</string>
|
||||
|
@ -505,6 +513,7 @@
|
|||
<string name="no_calendar_exists">Ingen kalender finnes</string>
|
||||
<string name="no_email_app_available">Ingen program for å behandle e-post adresse</string>
|
||||
<string name="no_items">Ingen gjenstander</string>
|
||||
<string name="no_map_app_availble">Ingen app tilgjengelig for å håndtere kart</string>
|
||||
<string name="no_mutliple_accounts_allowed">Kun én konto er tillatt</string>
|
||||
<string name="no_pdf_app_available">Ingen app tilgjengelig for å håndtere PDF</string>
|
||||
<string name="no_send_app">Ingen program for å sende valgt fil</string>
|
||||
|
@ -591,7 +600,9 @@
|
|||
<string name="prefs_imprint">Avtrykk</string>
|
||||
<string name="prefs_instant_behaviour_dialogTitle">Opprinnelig fil vil bli…</string>
|
||||
<string name="prefs_instant_behaviour_title">Opprinnelig fil vil bli…</string>
|
||||
<string name="prefs_instant_upload_path_use_date_subfolders_summary">Lagre i undermapper basert på dato</string>
|
||||
<string name="prefs_instant_upload_path_use_subfolders_title">Bruk undermapper</string>
|
||||
<string name="prefs_instant_upload_subfolder_rule_title">Alternativer for undermappe</string>
|
||||
<string name="prefs_keys_exist">Legg til ende-til-ende -kryptering på denne klienten</string>
|
||||
<string name="prefs_license">Lisens</string>
|
||||
<string name="prefs_lock">Appsikkerhet</string>
|
||||
|
@ -781,6 +792,8 @@
|
|||
<string name="stream_not_possible_headline">Intern strøming ikke mulig</string>
|
||||
<string name="stream_not_possible_message">Vennligst last ned media i stedet, eller bruk ekstern app.</string>
|
||||
<string name="strict_mode">Streng modus: ingen HTTP-tilkobling tillatt!</string>
|
||||
<string name="sub_folder_rule_day">År/Måned/Dag</string>
|
||||
<string name="sub_folder_rule_month">År/Måned</string>
|
||||
<string name="sub_folder_rule_year">År</string>
|
||||
<string name="subject_shared_with_you">\"%1$s\" er blitt delt med deg</string>
|
||||
<string name="subject_user_shared_with_you">%1$s delte \"%2$s\" med deg</string>
|
||||
|
@ -932,7 +945,9 @@
|
|||
<string name="wait_a_moment">Vent et øyeblikk…</string>
|
||||
<string name="wait_checking_credentials">Sjekker lagrede påloggingsdetaljer</string>
|
||||
<string name="wait_for_tmp_copy_from_private_storage">Kopierer fil fra privat lager</string>
|
||||
<string name="webview_version_check_alert_dialog_message">Vennligst oppdater Android systemets WebView-app for pålogging</string>
|
||||
<string name="webview_version_check_alert_dialog_positive_button_title">Oppdater</string>
|
||||
<string name="webview_version_check_alert_dialog_title">Oppdater Android systemets WebView</string>
|
||||
<string name="what_s_new_image">Hva er nytt-bilde</string>
|
||||
<string name="whats_new_skip">Hopp over</string>
|
||||
<string name="whats_new_title">Nytt i %1$s</string>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<string name="actionbar_copy">Kopiuj</string>
|
||||
<string name="actionbar_mkdir">Nowy katalog</string>
|
||||
<string name="actionbar_move">Przenieś</string>
|
||||
<string name="actionbar_move_or_copy">Przenieś lub kopiuj</string>
|
||||
<string name="actionbar_open_with">Otwórz za pomocą</string>
|
||||
<string name="actionbar_search">Wyszukaj</string>
|
||||
<string name="actionbar_see_details">Szczegóły</string>
|
||||
|
@ -944,7 +945,9 @@
|
|||
<string name="wait_a_moment">Proszę czekać…</string>
|
||||
<string name="wait_checking_credentials">Sprawdzanie danych</string>
|
||||
<string name="wait_for_tmp_copy_from_private_storage">Kopiowanie pliku z prywatnego magazynu</string>
|
||||
<string name="webview_version_check_alert_dialog_message">Aby się zalogować, zaktualizuj aplikację WebView systemu Android</string>
|
||||
<string name="webview_version_check_alert_dialog_positive_button_title">Aktualizuj</string>
|
||||
<string name="webview_version_check_alert_dialog_title">Zaktualizuj WebView systemu Android</string>
|
||||
<string name="what_s_new_image">Jaki jest nowy obraz</string>
|
||||
<string name="whats_new_skip">Pomiń</string>
|
||||
<string name="whats_new_title">Co nowego w %1$s</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">Удалить</string>
|
||||
<string name="file_detail_activity_error">Ошибка получения истории событий, связанных с файлом</string>
|
||||
<string name="file_details_no_content">Не удалось получить подробные сведения</string>
|
||||
<string name="file_downloader_notification_title_prefix">Скачивание \u0020</string>
|
||||
<string name="file_icon">Файл</string>
|
||||
<string name="file_keep">Сохранить</string>
|
||||
<string name="file_list_empty">Добавьте что-нибудь или синхронизируйте со своими устройствами!</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">Обриши</string>
|
||||
<string name="file_detail_activity_error">Грешка при добављању активности за фајл</string>
|
||||
<string name="file_details_no_content">Грешка при учитавању детаља</string>
|
||||
<string name="file_downloader_notification_title_prefix">Преузима се \u0020</string>
|
||||
<string name="file_icon">Фајл</string>
|
||||
<string name="file_keep">Задржи</string>
|
||||
<string name="file_list_empty">Отпремите неки садржај или синхронизујте са вашим уређајима.</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">Ta bort</string>
|
||||
<string name="file_detail_activity_error">Fel vid hämtning av aktiviteter för fil</string>
|
||||
<string name="file_details_no_content">Kunde inte läsa in detaljer</string>
|
||||
<string name="file_downloader_notification_title_prefix">Laddar ner \u0020</string>
|
||||
<string name="file_icon">Fil</string>
|
||||
<string name="file_keep">Behåll</string>
|
||||
<string name="file_list_empty">Ladda upp något eller synkronisera med dina enheter</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">Sil</string>
|
||||
<string name="file_detail_activity_error">Dosya işlemleri alınırken sorun çıktı</string>
|
||||
<string name="file_details_no_content">Ayrıntılar yüklenemedi</string>
|
||||
<string name="file_downloader_notification_title_prefix">İndiriliyor \u0020</string>
|
||||
<string name="file_icon">Dosya</string>
|
||||
<string name="file_keep">Tut</string>
|
||||
<string name="file_list_empty">Bazı içerikler yükleyin ya da aygıtlarınızla eşitleyin.</string>
|
||||
|
|
|
@ -323,7 +323,6 @@
|
|||
<string name="file_delete">Вилучити</string>
|
||||
<string name="file_detail_activity_error">Помилка з отриманням дії для файлу</string>
|
||||
<string name="file_details_no_content">Не вдалося завантажити подробиці</string>
|
||||
<string name="file_downloader_notification_title_prefix">Звантаження \u0020</string>
|
||||
<string name="file_icon">Файл</string>
|
||||
<string name="file_keep">Зберегти</string>
|
||||
<string name="file_list_empty">Додати дані або синхронізувати з вашими пристроями.</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">删除</string>
|
||||
<string name="file_detail_activity_error">获取文件动态时出错</string>
|
||||
<string name="file_details_no_content">加载详情失败</string>
|
||||
<string name="file_downloader_notification_title_prefix">下载中 \u0020</string>
|
||||
<string name="file_icon">文件</string>
|
||||
<string name="file_keep">保留</string>
|
||||
<string name="file_list_empty">上传一些内容或与您的设备同步。</string>
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<string name="file_delete">刪除</string>
|
||||
<string name="file_detail_activity_error">取得檔案活動時發生錯誤</string>
|
||||
<string name="file_details_no_content">載入詳細資訊失敗</string>
|
||||
<string name="file_downloader_notification_title_prefix">正在下載 \u0020</string>
|
||||
<string name="file_icon">檔案</string>
|
||||
<string name="file_keep">保留</string>
|
||||
<string name="file_list_empty">上傳一些內容或與您的裝置同步。</string>
|
||||
|
|
|
@ -162,7 +162,6 @@
|
|||
<string name="uploads_view_upload_status_fetching_server_version">Fetching server version…</string>
|
||||
<string name="uploads_view_later_waiting_to_upload">Waiting to upload</string>
|
||||
<string name="uploads_view_group_header" translatable="false">%1$s (%2$d)</string>
|
||||
<string name="file_downloader_notification_title_prefix">Downloading \u0020</string>
|
||||
<string name="downloader_download_in_progress_ticker">Downloading…</string>
|
||||
<string name="downloader_download_in_progress_content">%1$d%% Downloading %2$s</string>
|
||||
<string name="downloader_download_succeeded_ticker">Downloaded</string>
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
<item name="colorPrimary">@color/text_color</item>
|
||||
<item name="colorOnSurface">@color/text_color</item>
|
||||
<item name="colorError">@color/hwSecurityRed</item>
|
||||
<item name="editTextStyle">@style/Widget.MaterialComponents.TextInputEditText.OutlinedBox</item>
|
||||
<item name="editTextStyle">@style/Widget.Material3.TextInputEditText.OutlinedBox</item>
|
||||
</style>
|
||||
|
||||
<style name="TextInputLayoutInputWarning" parent="Widget.App.TextInputLayout">
|
||||
|
@ -102,7 +102,7 @@
|
|||
<item name="android:buttonBarButtonStyle">@style/FallbackTheming.Dialog.ButtonStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="FallbackTheming.Dialog.ButtonStyle" parent="Widget.MaterialComponents.Button.TextButton.Dialog">
|
||||
<style name="FallbackTheming.Dialog.ButtonStyle" parent="Widget.Material3.Button.TextButton.Dialog">
|
||||
<item name="android:textColor">@color/text_color</item>
|
||||
</style>
|
||||
|
||||
|
@ -363,7 +363,7 @@
|
|||
|
||||
<style name="Widget.App.Login.TextInputLayout" parent="Widget.Material3.TextInputLayout.OutlinedBox">
|
||||
<item name="materialThemeOverlay">@style/ThemeOverlay.App.Login.TextInputLayout</item>
|
||||
<item name="shapeAppearance">@style/ShapeAppearance.MaterialComponents.SmallComponent</item>
|
||||
<item name="shapeAppearance">@style/ShapeAppearance.Material3.SmallComponent</item>
|
||||
<item name="hintTextColor">?attr/colorOnSurface</item>
|
||||
</style>
|
||||
|
||||
|
@ -371,9 +371,9 @@
|
|||
<item name="colorPrimary">@color/white</item>
|
||||
<item name="colorOnSurface">@color/white</item>
|
||||
<item name="colorError">@color/hwSecurityRed</item>
|
||||
<item name="textAppearanceSubtitle1">@style/TextAppearance.MaterialComponents.Subtitle1</item>
|
||||
<item name="textAppearanceCaption">@style/TextAppearance.MaterialComponents.Caption</item>
|
||||
<item name="editTextStyle">@style/Widget.MaterialComponents.TextInputEditText.OutlinedBox</item>
|
||||
<item name="textAppearanceSubtitle1">@style/TextAppearance.Material3.BodyLarge</item>
|
||||
<item name="textAppearanceCaption">@style/TextAppearance.Material3.BodySmall</item>
|
||||
<item name="editTextStyle">@style/Widget.Material3.TextInputEditText.OutlinedBox</item>
|
||||
</style>
|
||||
|
||||
<style name="TextInputLayoutLogin" parent="Widget.Material3.TextInputLayout.OutlinedBox">
|
||||
|
@ -476,11 +476,11 @@
|
|||
</style>
|
||||
|
||||
|
||||
<style name="ThemeOverlay.App.BottomSheetDialog" parent="@style/ThemeOverlay.MaterialComponents.BottomSheetDialog">
|
||||
<style name="ThemeOverlay.App.BottomSheetDialog" parent="@style/ThemeOverlay.Material3.BottomSheetDialog">
|
||||
<item name="bottomSheetStyle">@style/App.BottomSheetDialog</item>
|
||||
</style>
|
||||
|
||||
<style name="App.BottomSheetDialog" parent="Widget.MaterialComponents.BottomSheet.Modal">
|
||||
<style name="App.BottomSheetDialog" parent="Widget.Material3.BottomSheet.Modal">
|
||||
<item name="backgroundTint">@color/bg_default</item>
|
||||
</style>
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class LocalConnectionTest {
|
|||
|
||||
// THEN
|
||||
// no binding is performed
|
||||
verify(exactly = 0) { context.bindService(any(), any(), any()) }
|
||||
verify(exactly = 0) { context.bindService(any(), any(), Context.BIND_AUTO_CREATE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -76,12 +76,12 @@ class LocalConnectionTest {
|
|||
|
||||
// WHEN
|
||||
// bind requested
|
||||
every { context.bindService(mockIntent, any(), any()) } returns true
|
||||
every { context.bindService(mockIntent!!, any(), Context.BIND_AUTO_CREATE) } returns true
|
||||
connection.bind()
|
||||
|
||||
// THEN
|
||||
// service bound
|
||||
verify { context.bindService(mockIntent, any(), any()) }
|
||||
verify { context.bindService(mockIntent!!, any(), Context.BIND_AUTO_CREATE) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -9,5 +9,10 @@ android.nonTransitiveRClass=false
|
|||
android.nonFinalResIds=false
|
||||
#android.debug.obsoleteApi=true
|
||||
|
||||
# Minimum max heap space to get reliable builds
|
||||
org.gradle.jvmargs=-Xmx1g
|
||||
|
||||
# JVM arguments to optimize heap usage, enable heap dump on out-of-memory errors, and set the file encoding
|
||||
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
kotlin.daemon.jvmargs=-Xmx4096m
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.configureondemand=true
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
DO NOT TOUCH; GENERATED BY DRONE
|
||||
<span class="mdl-layout-title">Lint Report: 75 warnings</span>
|
||||
<span class="mdl-layout-title">Lint Report: 74 warnings</span>
|
||||
|
|
Loading…
Reference in New Issue