diff --git a/app/src/androidTest/java/org/mozilla/fenix/AppRequestInterceptor.kt b/app/src/androidTest/java/org/mozilla/fenix/AppRequestInterceptor.kt index 3819ec015..f59bb885e 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/AppRequestInterceptor.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/AppRequestInterceptor.kt @@ -22,10 +22,11 @@ class AppRequestInterceptor(private val context: Context) : RequestInterceptor { uri: String, hasUserGesture: Boolean, isSameDomain: Boolean, - isRedirect: Boolean + isRedirect: Boolean, + isDirectNavigation: Boolean ): RequestInterceptor.InterceptionResponse? { return appContext.components.services.accountsAuthFeature.interceptor.onLoadRequest( - engineSession, uri, hasUserGesture, isSameDomain, isRedirect + engineSession, uri, hasUserGesture, isSameDomain, isRedirect, isDirectNavigation ) } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt index 9fe33f294..26eee5e0b 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt @@ -173,6 +173,7 @@ class ContextMenusTest { } @Test + @Ignore("Intermittent: https://github.com/mozilla-mobile/fenix/issues/12309") fun verifyContextSaveImage() { val pageLinks = TestAssetHelper.getGenericAsset(mockWebServer, 4) @@ -197,6 +198,7 @@ class ContextMenusTest { } @Test + @Ignore("Intermittent: https://github.com/mozilla-mobile/fenix/issues/12309") fun verifyContextMixedVariations() { val pageLinks = TestAssetHelper.getGenericAsset(mockWebServer, 4) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt index 14f5b94e3..67f3020bc 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt @@ -43,7 +43,7 @@ class ThreeDotMenuMainTest { @JvmStatic fun setDevicePreference() { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - mDevice.executeShellCommand("settings put secure long_press_timeout 1500") + mDevice.executeShellCommand("settings put secure long_press_timeout 3000") } } diff --git a/app/src/main/java/org/mozilla/fenix/AppRequestInterceptor.kt b/app/src/main/java/org/mozilla/fenix/AppRequestInterceptor.kt index d03aed8ba..eca6187c5 100644 --- a/app/src/main/java/org/mozilla/fenix/AppRequestInterceptor.kt +++ b/app/src/main/java/org/mozilla/fenix/AppRequestInterceptor.kt @@ -21,10 +21,11 @@ class AppRequestInterceptor(private val context: Context) : RequestInterceptor { uri: String, hasUserGesture: Boolean, isSameDomain: Boolean, - isRedirect: Boolean + isRedirect: Boolean, + isDirectNavigation: Boolean ): RequestInterceptor.InterceptionResponse? { return context.components.services.appLinksInterceptor - .onLoadRequest(engineSession, uri, hasUserGesture, isSameDomain, isRedirect) + .onLoadRequest(engineSession, uri, hasUserGesture, isSameDomain, isRedirect, isDirectNavigation) } override fun onErrorRequest( diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index 541dbf6dc..c59a39990 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -63,8 +63,8 @@ import org.mozilla.fenix.exceptions.ExceptionsFragmentDirections import org.mozilla.fenix.ext.alreadyOnDestination import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.nav -import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.resetPoliciesAfter +import org.mozilla.fenix.ext.settings import org.mozilla.fenix.home.HomeFragmentDirections import org.mozilla.fenix.home.intent.CrashReporterIntentProcessor import org.mozilla.fenix.home.intent.DeepLinkIntentProcessor @@ -100,7 +100,7 @@ import org.mozilla.fenix.utils.RunWhenReadyQueue * - browser screen */ @SuppressWarnings("TooManyFunctions", "LargeClass") -open class HomeActivity : LocaleAwareAppCompatActivity() { +open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { private var webExtScope: CoroutineScope? = null lateinit var themeManager: ThemeManager @@ -392,7 +392,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity() { * Returns the [supportActionBar], inflating it if necessary. * Everyone should call this instead of supportActionBar. */ - fun getSupportActionBarAndInflateIfNecessary(): ActionBar { + override fun getSupportActionBarAndInflateIfNecessary(): ActionBar { if (!isToolbarInflated) { navigationToolbar = navigationToolbarStub.inflate() as Toolbar diff --git a/app/src/main/java/org/mozilla/fenix/NavHostActivity.kt b/app/src/main/java/org/mozilla/fenix/NavHostActivity.kt new file mode 100644 index 000000000..a194c0eb4 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/NavHostActivity.kt @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix + +import androidx.appcompat.app.ActionBar + +/** + * Interface for the main activity in a single-activity architecture. + * All fragments will be displayed inside this activity. + */ +interface NavHostActivity { + + /** + * Returns the support action bar, inflating it if necessary. + * Everyone should call this instead of supportActionBar. + */ + fun getSupportActionBarAndInflateIfNecessary(): ActionBar +} diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt index 933b01e2c..28ef5e567 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt @@ -5,10 +5,11 @@ package org.mozilla.fenix.addons import android.content.Intent -import android.net.Uri +import android.content.Intent.ACTION_VIEW import android.os.Bundle import android.view.View import androidx.annotation.StringRes +import androidx.core.net.toUri import androidx.fragment.app.Fragment import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager @@ -26,7 +27,7 @@ private const val LEARN_MORE_URL = /** * A fragment to show the permissions of an add-on. */ -class AddonPermissionsDetailsFragment : Fragment(R.layout.fragment_add_on_permissions), View.OnClickListener { +class AddonPermissionsDetailsFragment : Fragment(R.layout.fragment_add_on_permissions) { private val args by navArgs() @@ -55,12 +56,9 @@ class AddonPermissionsDetailsFragment : Fragment(R.layout.fragment_add_on_permis } private fun bindLearnMore(view: View) { - view.learn_more_label.setOnClickListener(this) - } - - override fun onClick(v: View?) { - val intent = - Intent(Intent.ACTION_VIEW).setData(Uri.parse(LEARN_MORE_URL)) - startActivity(intent) + view.learn_more_label.setOnClickListener { + val intent = Intent(ACTION_VIEW, LEARN_MORE_URL.toUri()) + startActivity(intent) + } } } diff --git a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt index b95d14715..2016ef63a 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt @@ -24,7 +24,6 @@ import mozilla.components.feature.app.links.AppLinksUseCases import mozilla.components.feature.contextmenu.ContextMenuCandidate import mozilla.components.feature.readerview.ReaderViewFeature import mozilla.components.feature.search.SearchFeature -import mozilla.components.feature.session.TrackingProtectionUseCases import mozilla.components.feature.sitepermissions.SitePermissions import mozilla.components.feature.tab.collections.TabCollection import mozilla.components.feature.tabs.WindowFeature @@ -207,11 +206,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler { override fun navToTrackingProtectionPanel(session: Session) { val navController = findNavController() - val useCase = TrackingProtectionUseCases( - sessionManager = requireComponents.core.sessionManager, - engine = requireComponents.core.engine - ) - useCase.containsException(session) { contains -> + requireComponents.useCases.trackingProtectionUseCases.containsException(session.id) { contains -> val isEnabled = session.trackerBlockingEnabled && !contains val directions = BrowserFragmentDirections.actionBrowserFragmentToTrackingProtectionPanelDialogFragment( diff --git a/app/src/main/java/org/mozilla/fenix/components/TabCollectionStorage.kt b/app/src/main/java/org/mozilla/fenix/components/TabCollectionStorage.kt index ba6af9b1e..6fe835e20 100644 --- a/app/src/main/java/org/mozilla/fenix/components/TabCollectionStorage.kt +++ b/app/src/main/java/org/mozilla/fenix/components/TabCollectionStorage.kt @@ -84,11 +84,7 @@ class TabCollectionStorage( } fun removeTabFromCollection(tabCollection: TabCollection, tab: Tab) { - if (tabCollection.tabs.size == 1) { - removeCollection(tabCollection) - } else { - collectionStorage.removeTabFromCollection(tabCollection, tab) - } + collectionStorage.removeTabFromCollection(tabCollection, tab) } fun renameCollection(tabCollection: TabCollection, title: String) { diff --git a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt index c40cbc901..08469e9c3 100644 --- a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt +++ b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt @@ -18,6 +18,7 @@ import mozilla.components.feature.pwa.WebAppUseCases import mozilla.components.feature.search.SearchUseCases import mozilla.components.feature.session.SessionUseCases import mozilla.components.feature.session.SettingsUseCases +import mozilla.components.feature.session.TrackingProtectionUseCases import mozilla.components.feature.tabs.TabsUseCases import org.mozilla.fenix.utils.Mockable @@ -42,7 +43,7 @@ class UseCases( /** * Use cases that provide tab management. */ - val tabsUseCases: TabsUseCases by lazy { TabsUseCases(sessionManager) } + val tabsUseCases: TabsUseCases by lazy { TabsUseCases(store, sessionManager) } /** * Use cases that provide search engine integration. @@ -65,4 +66,6 @@ class UseCases( val contextMenuUseCases by lazy { ContextMenuUseCases(sessionManager, store) } val engineSessionUseCases by lazy { EngineSessionUseCases(sessionManager) } + + val trackingProtectionUseCases by lazy { TrackingProtectionUseCases(store, engine) } } diff --git a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt index 2066e0dbd..ea853bd94 100644 --- a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt @@ -11,7 +11,6 @@ import androidx.core.view.isVisible import androidx.navigation.fragment.navArgs import kotlinx.android.synthetic.main.component_browser_top_toolbar.* import kotlinx.android.synthetic.main.fragment_browser.* -import kotlinx.android.synthetic.main.fragment_browser.view.* import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.browser.session.Session import mozilla.components.concept.engine.manifest.WebAppManifestParser @@ -22,7 +21,6 @@ import mozilla.components.feature.pwa.feature.ManifestUpdateFeature import mozilla.components.feature.pwa.feature.WebAppActivityFeature import mozilla.components.feature.pwa.feature.WebAppHideToolbarFeature import mozilla.components.feature.pwa.feature.WebAppSiteControlsFeature -import mozilla.components.feature.session.TrackingProtectionUseCases import mozilla.components.feature.sitepermissions.SitePermissions import mozilla.components.support.base.feature.UserInteractionHandler import mozilla.components.support.base.feature.ViewBoundFeatureWrapper @@ -171,11 +169,7 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler } override fun navToTrackingProtectionPanel(session: Session) { - val useCase = TrackingProtectionUseCases( - sessionManager = requireComponents.core.sessionManager, - engine = requireComponents.core.engine - ) - useCase.containsException(session) { contains -> + requireComponents.useCases.trackingProtectionUseCases.containsException(session.id) { contains -> val isEnabled = session.trackerBlockingEnabled && !contains val directions = ExternalAppBrowserFragmentDirections diff --git a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt index 10485d3ee..8f193f222 100644 --- a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt @@ -44,10 +44,7 @@ class ExceptionsFragment : Fragment() { savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_exceptions, container, false) - trackingProtectionUseCases = TrackingProtectionUseCases( - sessionManager = view.context.components.core.sessionManager, - engine = view.context.components.core.engine - ) + trackingProtectionUseCases = view.context.components.useCases.trackingProtectionUseCases exceptionsStore = StoreProvider.get(this) { ExceptionsFragmentStore( ExceptionsFragmentState( diff --git a/app/src/main/java/org/mozilla/fenix/ext/Ads.kt b/app/src/main/java/org/mozilla/fenix/ext/Ads.kt deleted file mode 100644 index 7bf818598..000000000 --- a/app/src/main/java/org/mozilla/fenix/ext/Ads.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.fenix.ext - -import org.mozilla.fenix.search.telemetry.SearchProviderModel - -fun SearchProviderModel.containsAds(urlList: List): Boolean { - return urlList.containsAds(this.extraAdServersRegexps) -} - -private fun String.isAd(adRegexps: List): Boolean { - for (adsRegex in adRegexps) { - if (Regex(adsRegex).containsMatchIn(this)) { - return true - } - } - return false -} - -private fun List.containsAds(adRegexps: List): Boolean { - for (url in this) { - if (url.isAd(adRegexps)) { - return true - } - } - return false -} diff --git a/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt b/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt index 7da50f968..92433aae5 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt @@ -13,7 +13,7 @@ import androidx.navigation.NavOptions import androidx.navigation.Navigator import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.findNavController -import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.NavHostActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.Components @@ -43,7 +43,7 @@ fun Fragment.getPreferenceKey(@StringRes resourceId: Int): String = getString(re */ fun Fragment.showToolbar(title: String) { (requireActivity() as AppCompatActivity).title = title - (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary().show() + (activity as NavHostActivity).getSupportActionBarAndInflateIfNecessary().show() } /** diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index f2993aa86..0b6531b43 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -20,7 +20,6 @@ import android.view.accessibility.AccessibilityEvent import android.widget.Button import android.widget.LinearLayout import android.widget.PopupWindow -import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet @@ -133,11 +132,11 @@ class HomeFragment : Fragment() { private val collectionStorageObserver = object : TabCollectionStorage.Observer { override fun onCollectionCreated(title: String, sessions: List) { - scrollAndAnimateCollection(sessions.size) + scrollAndAnimateCollection() } override fun onTabsAdded(tabCollection: TabCollection, sessions: List) { - scrollAndAnimateCollection(sessions.size, tabCollection) + scrollAndAnimateCollection(tabCollection) } override fun onCollectionRenamed(tabCollection: TabCollection, title: String) { @@ -218,7 +217,8 @@ class HomeFragment : Fragment() { sessionControlView = SessionControlView( view.sessionControlRecyclerView, sessionControlInteractor, - homeViewModel + homeViewModel, + requireComponents.core.store.state.normalTabs.isNotEmpty() ) updateSessionControlView(view) @@ -470,11 +470,10 @@ class HomeFragment : Fragment() { } } - private fun showDeleteCollectionPrompt(tabCollection: TabCollection) { + private fun showDeleteCollectionPrompt(tabCollection: TabCollection, title: String?, message: String) { val context = context ?: return AlertDialog.Builder(context).apply { - val message = - context.getString(R.string.tab_collection_dialog_message, tabCollection.title) + setTitle(title) setMessage(message) setNegativeButton(R.string.tab_collection_dialog_negative) { dialog: DialogInterface, _ -> dialog.cancel() @@ -787,7 +786,6 @@ class HomeFragment : Fragment() { } private fun scrollAndAnimateCollection( - tabsAddedToCollectionSize: Int, changedCollection: TabCollection? = null ) { if (view != null) { @@ -818,7 +816,7 @@ class HomeFragment : Fragment() { ) { super.onScrollStateChanged(recyclerView, newState) if (newState == SCROLL_STATE_IDLE) { - animateCollection(tabsAddedToCollectionSize, indexOfCollection) + animateCollection(indexOfCollection) recyclerView.removeOnScrollListener(this) } } @@ -826,13 +824,13 @@ class HomeFragment : Fragment() { recyclerView.addOnScrollListener(onScrollListener) recyclerView.smoothScrollToPosition(indexOfCollection) } else { - animateCollection(tabsAddedToCollectionSize, indexOfCollection) + animateCollection(indexOfCollection) } } } } - private fun animateCollection(addedTabsSize: Int, indexOfCollection: Int) { + private fun animateCollection(indexOfCollection: Int) { viewLifecycleOwner.lifecycleScope.launch { val viewHolder = sessionControlView!!.view.findViewHolderForAdapterPosition(indexOfCollection) @@ -859,26 +857,20 @@ class HomeFragment : Fragment() { ?.setDuration(FADE_ANIM_DURATION) ?.setListener(listener)?.start() }.invokeOnCompletion { - showSavedSnackbar(addedTabsSize) + showSavedSnackbar() } } - private fun showSavedSnackbar(tabSize: Int) { + private fun showSavedSnackbar() { viewLifecycleOwner.lifecycleScope.launch { delay(ANIM_SNACKBAR_DELAY) view?.let { view -> - @StringRes - val stringRes = if (tabSize > 1) { - R.string.create_collection_tabs_saved - } else { - R.string.create_collection_tab_saved - } FenixSnackbar.make( view = view, duration = Snackbar.LENGTH_LONG, isDisplayedWithBrowserToolbar = false ) - .setText(view.context.getString(stringRes)) + .setText(view.context.getString(R.string.create_collection_tabs_saved_new_collection)) .setAnchorView(snackbarAnchorView) .show() } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt index d19f3c1af..c9441f99e 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt @@ -108,7 +108,8 @@ class AdapterItemDiffCallback : DiffUtil.ItemCallback() { } class SessionControlAdapter( - private val interactor: SessionControlInteractor + private val interactor: SessionControlInteractor, + private val hasNormalTabsOpened: Boolean ) : ListAdapter(AdapterItemDiffCallback()) { // This method triggers the ComplexMethod lint error when in fact it's quite simple. @@ -119,7 +120,8 @@ class SessionControlAdapter( ButtonTipViewHolder.LAYOUT_ID -> ButtonTipViewHolder(view, interactor) TopSiteViewHolder.LAYOUT_ID -> TopSiteViewHolder(view, interactor) PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, interactor) - NoCollectionsMessageViewHolder.LAYOUT_ID -> NoCollectionsMessageViewHolder(view, interactor) + NoCollectionsMessageViewHolder.LAYOUT_ID -> + NoCollectionsMessageViewHolder(view, interactor, hasNormalTabsOpened) CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view) CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, interactor) TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, interactor, differentLastItem = true) diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt index aa0744459..74b4e1bd0 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt @@ -136,7 +136,7 @@ class DefaultSessionControlController( private val getListOfTabs: () -> List, private val hideOnboarding: () -> Unit, private val registerCollectionStorageObserver: () -> Unit, - private val showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit, + private val showDeleteCollectionPrompt: (tabCollection: TabCollection, title: String?, message: String) -> Unit, private val openSettingsScreen: () -> Unit, private val openWhatsNewLink: () -> Unit, private val openPrivacyNotice: () -> Unit, @@ -196,8 +196,14 @@ class DefaultSessionControlController( override fun handleCollectionRemoveTab(collection: TabCollection, tab: ComponentTab) { metrics.track(Event.CollectionTabRemoved) - viewLifecycleScope.launch(Dispatchers.IO) { - tabCollectionStorage.removeTabFromCollection(collection, tab) + if (collection.tabs.size == 1) { + val title = activity.resources.getString(R.string.delete_tab_and_collection_dialog_title, collection.title) + val message = activity.resources.getString(R.string.delete_tab_and_collection_dialog_message) + showDeleteCollectionPrompt(collection, title, message) + } else { + viewLifecycleScope.launch(Dispatchers.IO) { + tabCollectionStorage.removeTabFromCollection(collection, tab) + } } } @@ -207,7 +213,8 @@ class DefaultSessionControlController( } override fun handleDeleteCollectionTapped(collection: TabCollection) { - showDeleteCollectionPrompt(collection) + val message = activity.resources.getString(R.string.tab_collection_dialog_message, collection.title) + showDeleteCollectionPrompt(collection, null, message) } override fun handleOpenInPrivateTabClicked(topSite: TopSite) { diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt index 41e4b1ad0..d24b62662 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt @@ -114,12 +114,13 @@ private fun collectionTabItems(collection: TabCollection) = collection.tabs.mapI class SessionControlView( override val containerView: View?, interactor: SessionControlInteractor, - private var homeScreenViewModel: HomeScreenViewModel + private var homeScreenViewModel: HomeScreenViewModel, + private val hasNormalTabsOpened: Boolean ) : LayoutContainer { val view: RecyclerView = containerView as RecyclerView - private val sessionControlAdapter = SessionControlAdapter(interactor) + private val sessionControlAdapter = SessionControlAdapter(interactor, hasNormalTabsOpened) init { view.apply { diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoCollectionsMessageViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoCollectionsMessageViewHolder.kt index 8c7421856..1882351c5 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoCollectionsMessageViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoCollectionsMessageViewHolder.kt @@ -5,6 +5,7 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders import android.view.View +import androidx.core.view.isVisible import kotlinx.android.synthetic.main.no_collections_message.view.* import org.mozilla.fenix.R import org.mozilla.fenix.ext.ViewHolder @@ -12,13 +13,15 @@ import org.mozilla.fenix.home.sessioncontrol.CollectionInteractor open class NoCollectionsMessageViewHolder( view: View, - interactor: CollectionInteractor + interactor: CollectionInteractor, + hasNormalTabsOpened: Boolean ) : ViewHolder(view) { init { view.add_tabs_to_collections_button.setOnClickListener { interactor.onAddTabsToCollectionTapped() } + view.add_tabs_to_collections_button.isVisible = hasNormalTabsOpened } companion object { const val LAYOUT_ID = R.layout.no_collections_message diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt index 6507c8668..decb6bef8 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt @@ -37,7 +37,7 @@ import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.base.feature.UserInteractionHandler -import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.NavHostActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.StoreProvider @@ -147,7 +147,7 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan override fun onResume() { super.onResume() - (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary().show() + (activity as NavHostActivity).getSupportActionBarAndInflateIfNecessary().show() // Reload bookmarks when returning to this fragment in case they have been edited val args by navArgs() diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt index 1c2ece81c..a578b898f 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt @@ -31,7 +31,7 @@ import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType import mozilla.components.support.ktx.android.content.getColorFromAttr import mozilla.components.support.ktx.android.view.hideKeyboard -import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.NavHostActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.metrics.Event @@ -111,15 +111,13 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) { } private fun initToolbar() { - val activity = activity as? AppCompatActivity - val actionBar = (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary() + val activity = activity as AppCompatActivity + val actionBar = (activity as NavHostActivity).getSupportActionBarAndInflateIfNecessary() val toolbar = activity.findViewById(R.id.navigationToolbar) - context?.let { - toolbar?.setToolbarColors( - foreground = it.getColorFromAttr(R.attr.primaryText), - background = it.getColorFromAttr(R.attr.foundation) - ) - } + toolbar?.setToolbarColors( + foreground = activity.getColorFromAttr(R.attr.primaryText), + background = activity.getColorFromAttr(R.attr.foundation) + ) actionBar.show() } diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt index cbfab61c6..37bc6d5f0 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt @@ -101,6 +101,7 @@ class SearchFragment : Fragment(), UserInteractionHandler { requireComponents.analytics.metrics.track(Event.InteractWithSearchURLArea) + val areShortcutsAvailable = areShortcutsAvailable() searchStore = StoreProvider.get(this) { SearchFragmentStore( SearchFragmentState( @@ -111,7 +112,10 @@ class SearchFragment : Fragment(), UserInteractionHandler { defaultEngineSource = currentSearchEngine, showSearchSuggestions = shouldShowSearchSuggestions(isPrivate), showSearchSuggestionsHint = false, - showSearchShortcuts = requireContext().settings().shouldShowSearchShortcuts && url.isEmpty(), + showSearchShortcuts = requireContext().settings().shouldShowSearchShortcuts && + url.isEmpty() && + areShortcutsAvailable, + areShortcutsAvailable = areShortcutsAvailable, showClipboardSuggestions = requireContext().settings().shouldShowClipboardSuggestions, showHistorySuggestions = requireContext().settings().shouldShowHistorySuggestions, showBookmarkSuggestions = requireContext().settings().shouldShowBookmarkSuggestions, @@ -334,6 +338,12 @@ class SearchFragment : Fragment(), UserInteractionHandler { ) } + // Users can from this fragment go to install/uninstall search engines and then return. + val areShortcutsAvailable = areShortcutsAvailable() + if (searchStore.state.areShortcutsAvailable != areShortcutsAvailable) { + searchStore.dispatch(SearchFragmentAction.UpdateShortcutsAvailability(areShortcutsAvailable)) + } + if (!permissionDidUpdate) { toolbarView.view.edit.focus() } @@ -431,6 +441,8 @@ class SearchFragment : Fragment(), UserInteractionHandler { private fun updateSearchShortcutsIcon(searchState: SearchFragmentState) { view?.apply { + search_shortcuts_button.isVisible = searchState.areShortcutsAvailable + val showShortcuts = searchState.showSearchShortcuts search_shortcuts_button.isChecked = showShortcuts @@ -441,7 +453,16 @@ class SearchFragment : Fragment(), UserInteractionHandler { } } + /** + * Return if the user has *at least 2* installed search engines. + * Useful to decide whether to show / enable certain functionalities. + */ + private fun areShortcutsAvailable() = + requireContext().components.search.provider.installedSearchEngines(requireContext()) + .list.size >= MINIMUM_SEARCH_ENGINES_NUMBER_TO_SHOW_SHORTCUTS + companion object { private const val REQUEST_CODE_CAMERA_PERMISSIONS = 1 + private const val MINIMUM_SEARCH_ENGINES_NUMBER_TO_SHOW_SHORTCUTS = 2 } } diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchFragmentStore.kt b/app/src/main/java/org/mozilla/fenix/search/SearchFragmentStore.kt index e8e270924..7ef4aa16a 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchFragmentStore.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchFragmentStore.kt @@ -41,6 +41,8 @@ sealed class SearchEngineSource { * @property showSearchSuggestions Whether or not to show search suggestions from the search engine in the AwesomeBar * @property showSearchSuggestionsHint Whether or not to show search suggestions in private hint panel * @property showSearchShortcuts Whether or not to show search shortcuts in the AwesomeBar + * @property areShortcutsAvailable Whether or not there are >=2 search engines installed + * so to know to present users with certain options or not. * @property showClipboardSuggestions Whether or not to show clipboard suggestion in the AwesomeBar * @property showHistorySuggestions Whether or not to show history suggestions in the AwesomeBar * @property showBookmarkSuggestions Whether or not to show the bookmark suggestion in the AwesomeBar @@ -55,6 +57,7 @@ data class SearchFragmentState( val showSearchSuggestions: Boolean, val showSearchSuggestionsHint: Boolean, val showSearchShortcuts: Boolean, + val areShortcutsAvailable: Boolean, val showClipboardSuggestions: Boolean, val showHistorySuggestions: Boolean, val showBookmarkSuggestions: Boolean, @@ -71,6 +74,7 @@ sealed class SearchFragmentAction : Action { data class SearchShortcutEngineSelected(val engine: SearchEngine) : SearchFragmentAction() data class SelectNewDefaultSearchEngine(val engine: SearchEngine) : SearchFragmentAction() data class ShowSearchShortcutEnginePicker(val show: Boolean) : SearchFragmentAction() + data class UpdateShortcutsAvailability(val areShortcutsAvailable: Boolean) : SearchFragmentAction() data class AllowSearchSuggestionsInPrivateModePrompt(val show: Boolean) : SearchFragmentAction() data class UpdateQuery(val query: String) : SearchFragmentAction() } @@ -86,7 +90,9 @@ private fun searchStateReducer(state: SearchFragmentState, action: SearchFragmen showSearchShortcuts = false ) is SearchFragmentAction.ShowSearchShortcutEnginePicker -> - state.copy(showSearchShortcuts = action.show) + state.copy(showSearchShortcuts = action.show && state.areShortcutsAvailable) + is SearchFragmentAction.UpdateShortcutsAvailability -> + state.copy(areShortcutsAvailable = action.areShortcutsAvailable) is SearchFragmentAction.UpdateQuery -> state.copy(query = action.query) is SearchFragmentAction.SelectNewDefaultSearchEngine -> diff --git a/app/src/main/java/org/mozilla/fenix/search/telemetry/BaseSearchTelemetry.kt b/app/src/main/java/org/mozilla/fenix/search/telemetry/BaseSearchTelemetry.kt index d7c0b53b1..94fa72e42 100644 --- a/app/src/main/java/org/mozilla/fenix/search/telemetry/BaseSearchTelemetry.kt +++ b/app/src/main/java/org/mozilla/fenix/search/telemetry/BaseSearchTelemetry.kt @@ -82,14 +82,8 @@ abstract class BaseSearchTelemetry { abstract fun install(engine: Engine, store: BrowserStore) - internal fun getProviderForUrl(url: String): SearchProviderModel? { - for (provider in providerList) { - if (Regex(provider.regexp).containsMatchIn(url)) { - return provider - } - } - return null - } + internal fun getProviderForUrl(url: String): SearchProviderModel? = + providerList.find { provider -> provider.regexp.containsMatchIn(url) } internal fun installWebExtension( engine: Engine, diff --git a/app/src/main/java/org/mozilla/fenix/search/telemetry/SearchProviderModel.kt b/app/src/main/java/org/mozilla/fenix/search/telemetry/SearchProviderModel.kt index a1894c98e..ff8f64d00 100644 --- a/app/src/main/java/org/mozilla/fenix/search/telemetry/SearchProviderModel.kt +++ b/app/src/main/java/org/mozilla/fenix/search/telemetry/SearchProviderModel.kt @@ -6,11 +6,41 @@ package org.mozilla.fenix.search.telemetry data class SearchProviderModel( val name: String, - val regexp: String, + val regexp: Regex, val queryParam: String, - val codeParam: String = "", - val codePrefixes: List = ArrayList(), - val followOnParams: List = ArrayList(), - val extraAdServersRegexps: List = ArrayList(), - val followOnCookies: List = ArrayList() -) + val codeParam: String, + val codePrefixes: List, + val followOnParams: List, + val extraAdServersRegexps: List, + val followOnCookies: List +) { + + constructor( + name: String, + regexp: String, + queryParam: String, + codeParam: String = "", + codePrefixes: List = emptyList(), + followOnParams: List = emptyList(), + extraAdServersRegexps: List = emptyList(), + followOnCookies: List = emptyList() + ) : this( + name = name, + regexp = regexp.toRegex(), + queryParam = queryParam, + codeParam = codeParam, + codePrefixes = codePrefixes, + followOnParams = followOnParams, + extraAdServersRegexps = extraAdServersRegexps.map { it.toRegex() }, + followOnCookies = followOnCookies + ) + + /** + * Checks if any of the given URLs represent an ad from the search engine. + * Used to check if a clicked link was for an ad. + */ + fun containsAds(urlList: List) = urlList.any { url -> isAd(url) } + + private fun isAd(url: String) = + extraAdServersRegexps.any { adsRegex -> adsRegex.containsMatchIn(url) } +} diff --git a/app/src/main/java/org/mozilla/fenix/search/telemetry/ads/AdsTelemetry.kt b/app/src/main/java/org/mozilla/fenix/search/telemetry/ads/AdsTelemetry.kt index 645efc10e..97dfcc56d 100644 --- a/app/src/main/java/org/mozilla/fenix/search/telemetry/ads/AdsTelemetry.kt +++ b/app/src/main/java/org/mozilla/fenix/search/telemetry/ads/AdsTelemetry.kt @@ -10,7 +10,6 @@ import mozilla.components.concept.engine.Engine import org.json.JSONObject import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.MetricController -import org.mozilla.fenix.ext.containsAds import org.mozilla.fenix.search.telemetry.BaseSearchTelemetry import org.mozilla.fenix.search.telemetry.ExtensionInfo diff --git a/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt index 6cdf2235b..f210513db 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt @@ -14,7 +14,6 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.CompoundButton -import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope @@ -36,6 +35,7 @@ import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.searchengine.CustomSearchEngineStore import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.settings.SupportUtils import java.util.Locale @@ -93,7 +93,7 @@ class AddSearchEngineFragment : Fragment(), CompoundButton.OnCheckedChangeListen availableEngines.forEachIndexed(setupSearchEngineItem) - val engineItem = makeCustomButton(layoutInflater) + val engineItem = makeCustomButton(layoutInflater, res = resources) engineItem.id = CUSTOM_INDEX engineItem.radio_button.isChecked = selectedIndex == CUSTOM_INDEX engineViews.add(engineItem) @@ -115,8 +115,7 @@ class AddSearchEngineFragment : Fragment(), CompoundButton.OnCheckedChangeListen override fun onResume() { super.onResume() - (activity as AppCompatActivity).title = getString(R.string.search_engine_add_custom_search_engine_title) - (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary().show() + showToolbar(getString(R.string.search_engine_add_custom_search_engine_title)) } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { @@ -250,11 +249,12 @@ class AddSearchEngineFragment : Fragment(), CompoundButton.OnCheckedChangeListen toggleCustomForm(selectedIndex == -1) } - private fun makeCustomButton(layoutInflater: LayoutInflater): View { + private fun makeCustomButton(layoutInflater: LayoutInflater, res: Resources): View { val wrapper = layoutInflater .inflate(R.layout.custom_search_engine_radio_button, null) as ConstraintLayout wrapper.setOnClickListener { wrapper.radio_button.isChecked = true } wrapper.radio_button.setOnCheckedChangeListener(this) + wrapper.minHeight = res.getDimensionPixelSize(R.dimen.radio_button_preference_height) return wrapper } @@ -280,6 +280,7 @@ class AddSearchEngineFragment : Fragment(), CompoundButton.OnCheckedChangeListen engineIcon.setBounds(0, 0, iconSize, iconSize) wrapper.engine_icon.setImageDrawable(engineIcon) wrapper.overflow_menu.visibility = View.GONE + wrapper.minHeight = res.getDimensionPixelSize(R.dimen.radio_button_preference_height) return wrapper } diff --git a/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsExceptionsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsExceptionsFragment.kt index f177e0cd4..813e24591 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsExceptionsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsExceptionsFragment.kt @@ -28,7 +28,7 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import mozilla.components.feature.sitepermissions.SitePermissions -import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.NavHostActivity import org.mozilla.fenix.R import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.loadIntoView @@ -44,7 +44,7 @@ class SitePermissionsExceptionsFragment : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary().show() + (activity as NavHostActivity).getSupportActionBarAndInflateIfNecessary().show() } override fun onViewCreated(rootView: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt index d3272be44..56c761ef3 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt @@ -51,11 +51,11 @@ class TabTrayDialogFragment : AppCompatDialogFragment() { private val collectionStorageObserver = object : TabCollectionStorage.Observer { override fun onCollectionCreated(title: String, sessions: List) { - showCollectionSnackbar() + showCollectionSnackbar(sessions.size, true) } override fun onTabsAdded(tabCollection: TabCollection, sessions: List) { - showCollectionSnackbar() + showCollectionSnackbar(sessions.size) } } @@ -245,8 +245,19 @@ class TabTrayDialogFragment : AppCompatDialogFragment() { } } - private fun showCollectionSnackbar() { + private fun showCollectionSnackbar(tabSize: Int, isNewCollection: Boolean = false) { view.let { + val messageStringRes = when { + isNewCollection -> { + R.string.create_collection_tabs_saved_new_collection + } + tabSize > 1 -> { + R.string.create_collection_tabs_saved + } + else -> { + R.string.create_collection_tab_saved + } + } val snackbar = FenixSnackbar .make( duration = FenixSnackbar.LENGTH_LONG, @@ -254,7 +265,7 @@ class TabTrayDialogFragment : AppCompatDialogFragment() { view = (view as View) ) .setAnchorView(snackbarAnchor) - .setText(requireContext().getString(R.string.create_collection_tabs_saved)) + .setText(requireContext().getString(messageStringRes)) .setAction(requireContext().getString(R.string.create_collection_view)) { dismissAllowingStateLoss() findNavController().navigate( diff --git a/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelDialogFragment.kt index 570ed2ec9..b0257d02a 100644 --- a/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelDialogFragment.kt @@ -61,11 +61,7 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val components = requireComponents - trackingProtectionUseCases = TrackingProtectionUseCases( - sessionManager = components.core.sessionManager, - engine = components.core.engine - ) + trackingProtectionUseCases = requireComponents.useCases.trackingProtectionUseCases } override fun onCreateView( @@ -115,7 +111,7 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt private fun updateTrackers(session: Session) { trackingProtectionUseCases.fetchTrackingLogs( - session, + session.id, onSuccess = { trackingProtectionStore.dispatch(TrackingProtectionAction.TrackerLogChange(it)) }, @@ -150,10 +146,10 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt val session = context.components.core.sessionManager.findSessionById(args.sessionId) session?.let { if (isEnabled) { - trackingProtectionUseCases.removeException(it) + trackingProtectionUseCases.removeException(it.id) } else { context.metrics.track(Event.TrackingProtectionException) - trackingProtectionUseCases.addException(it) + trackingProtectionUseCases.addException(it.id) } with(context.components) { diff --git a/app/src/main/res/layout/component_locale_settings.xml b/app/src/main/res/layout/component_locale_settings.xml index 98ccd27cd..338f2868c 100644 --- a/app/src/main/res/layout/component_locale_settings.xml +++ b/app/src/main/res/layout/component_locale_settings.xml @@ -1,4 +1,7 @@ + @@ -46,6 +47,7 @@ android:id="@+id/edit_search_string" android:layout_width="match_parent" android:layout_height="wrap_content" + android:minHeight="@dimen/accessibility_min_height" android:hint="@string/search_add_custom_engine_search_string_hint" android:inputType="text" /> diff --git a/app/src/main/res/layout/custom_search_engine_radio_button.xml b/app/src/main/res/layout/custom_search_engine_radio_button.xml index 53eaada56..8ece2dbfe 100644 --- a/app/src/main/res/layout/custom_search_engine_radio_button.xml +++ b/app/src/main/res/layout/custom_search_engine_radio_button.xml @@ -20,7 +20,8 @@ android:textAppearance="?android:attr/textAppearanceListItem" android:layout_marginStart="@dimen/search_bar_search_engine_icon_padding" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent"/> diff --git a/app/src/main/res/layout/fragment_locale_settings.xml b/app/src/main/res/layout/fragment_locale_settings.xml index 2ce083109..eb8b403c7 100644 --- a/app/src/main/res/layout/fragment_locale_settings.xml +++ b/app/src/main/res/layout/fragment_locale_settings.xml @@ -1,4 +1,7 @@ + + + android:layout_height="48dp"> @@ -23,7 +26,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/locale_item_text_margin_start" - android:layout_marginTop="@dimen/locale_item_vertical_margin" + android:layout_marginEnd="@dimen/locale_item_text_margin_end" android:textColor="?primaryText" android:textAlignment="viewStart" app:layout_goneMarginStart="@dimen/locale_item_text_margin_gone_start" @@ -33,22 +36,24 @@ app:layout_constraintStart_toEndOf="@+id/locale_selected_icon" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" - app:layout_goneMarginBottom="@dimen/locale_item_vertical_margin" /> + tools:text="English (United States)" /> + app:layout_constraintVertical_chainStyle="packed" + tools:text="English (United States)" /> \ No newline at end of file diff --git a/app/src/main/res/layout/preference_cat_style.xml b/app/src/main/res/layout/preference_cat_style.xml index 5ab3d00a1..e42206621 100644 --- a/app/src/main/res/layout/preference_cat_style.xml +++ b/app/src/main/res/layout/preference_cat_style.xml @@ -1,13 +1,15 @@ + + android:textAlignment="viewStart" + app:fontFamily="@font/metropolis_semibold" /> diff --git a/app/src/main/res/layout/preference_widget_radiobutton.xml b/app/src/main/res/layout/preference_widget_radiobutton.xml index b534f4aab..ae73ed749 100644 --- a/app/src/main/res/layout/preference_widget_radiobutton.xml +++ b/app/src/main/res/layout/preference_widget_radiobutton.xml @@ -29,6 +29,7 @@ diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 5569af9c9..314f1e69a 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -807,6 +807,9 @@ Firefox Nightly anuévase cada nueche y tien carauterístiques esperimentales. Por embargu, ye menos estable. Baxa la versión beta del restolador pa una esperiencia más estable. + + Consiguir Firefox Beta p\'Android + Firefox Nightly mudó @@ -819,6 +822,9 @@ Dexa d\'usar esta aplicación darréu que nun va recibir más anovamientos de seguranza. Consigui la versión nueva de Nightly. \n\nPa tresferir los marcadores, anicios de sesión y l\'historial a otra aplicación, crea una cuenta de Firefox. + + Consiguir el Nightly nuevu + diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index b128ff917..8f825f6d1 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -698,6 +698,8 @@ Зразумела + + Немагчыма падзяліцца гэтай праграмай Даслаць на прыладу @@ -751,6 +753,9 @@ Адмяніць Пацвердзіць + + Дазволіць %1$s адкрыць %2$s ДАЗВОЛІЦЬ @@ -766,12 +771,18 @@ URL скапіраваны + + Гэта ўзор тэксту. Ён тут, каб паказаць, як тэкст будзе выглядаць пры павелічэнні або памяншэнні памеру з дапамогай гэтай налады. + + Зрабіць тэкст на сайтах большым ці меншым Памер шрыфту Аўтаматычны памер шрыфту + + Выдаліць дадзеныя аглядання Адкрытыя карткі @@ -788,12 +799,18 @@ Старонак: %d Кукі + + Вы выйдзеце з большасці сайтаў + + Кэшаваныя відарысы і файлы Дазволы для сайтаў Выдаліць звесткі аглядання Выдаляць звесткі аглядання пры выхадзе + + Аўтаматычна выдаляе дадзеныя аглядання, калі вы выбіраеце "Выйсці" ў галоўным меню Выйсці @@ -802,6 +819,15 @@ Выдаліць + + Дадзеныя аглядання выдалены + + + + Firefox Preview цяпер Firefox Nightly + + Firefox Nightly абнаўляецца кожную ноч і мае новыя эксперыментальныя магчымасці. + Аднак ён можа быць менш стабільным. Сцягніце нашу бэта-версію для больш стабільнай працы. Атрымаць Firefox для Android Beta @@ -835,8 +861,14 @@ Атрымайце максімум ад %s. + + Так, увайсці + + Уваход… Увайсці ў Firefox + + Не ўваходзіць Сінхранізацыя ўключана @@ -940,6 +972,8 @@ Даведацца больш Стандартная (прадвызначана) + + Блакуе менш трэкераў. Старонкі загружаюцца нармальна. Што блакуецца стандартнай аховай ад сачэння @@ -1149,6 +1183,13 @@ Увядзіце назву пошукавай сістэмы + + Увядзіце радок пошуку + + + Абнаўленне %s… + + Запусціць %s Міграцыя завершана @@ -1184,6 +1225,10 @@ Вы сапраўды хочаце выдаліць гэтае лагін? Выдаліць + + Тэкставае поле для рэдагавання вэб-адраса для ўваходу ў сістэму. + + Тэкставае поле для рэдагавання імені карыстальніка для ўваходу ў сістэму. Патрабуецца пароль diff --git a/app/src/main/res/values-cy/strings.xml b/app/src/main/res/values-cy/strings.xml index 573d7b3f2..6621b6eea 100644 --- a/app/src/main/res/values-cy/strings.xml +++ b/app/src/main/res/values-cy/strings.xml @@ -914,7 +914,7 @@ Mae Firefox Nightly wedi symud - Ni fydd yr ap hon yn derbyn diweddariadau diogelwch mwyach. Peidiwch a defnyddio’r ap hon a symud i’r Nightly newydd. + Ni fydd yr ap hwn yn derbyn diweddariadau diogelwch mwyach. Peidiwch â defnyddio’r ap hwn a newidiwch i’r Nightly newydd. \n\nEr mwyn trosglwyddo’ch nodau tudalen, eich mewngofnodion a’ch hanes i ap arall, crëwch gyfrif Firefox. Newid i’r Nightly newydd @@ -922,7 +922,7 @@ Mae Firefox Nightly wedi symud - Ni fydd yr ap hon yn derbyn diweddariadau diogelwch bellach. Estynnwch y Nightly newydd a pheidio a defnyddio’r ap hon. + Ni fydd yr ap hwn yn derbyn diweddariadau diogelwch bellach. Estynnwch y Nightly newydd a pheidio â defnyddio’r ap hwn bellach. \n\nEr mwyn trosglwyddo’ch nodau tudalen, eich mewngofnodion a’ch hanes i ap arall, crëwch gyfrif Firefox. Estyn y Nightly newydd diff --git a/app/src/main/res/values-es-rAR/strings.xml b/app/src/main/res/values-es-rAR/strings.xml index dbc3bdc13..c2d6cefbb 100644 --- a/app/src/main/res/values-es-rAR/strings.xml +++ b/app/src/main/res/values-es-rAR/strings.xml @@ -908,8 +908,6 @@ Elimina automáticamente los datos de navegación cuando seleccionás "Salir" en el menú principal Elimina automáticamente los datos de navegación cuando seleccionás "Salir" en el menú principal - - Historial de navegación Salir @@ -931,25 +929,22 @@ Firefox Nightly ahora es Firefox Preview - Firefox Nightly se actualiza todas las noches y tiene nuevas funciones experimentales. -        Sin embargo, puede ser menos estable. Descargá nuestro navegador beta para una experiencia más estable. + Firefox Nightly se actualiza todas las noches y tiene nuevas funciones experimentales.  Sin embargo, puede ser menos estable. Para una experiencia más estable descargá nuestro navegador beta. Obtené Firefox para Android Beta - Firefox Nightly se movió + Firefox Nightly cambió - Esta aplicación ya no va arecibir actualizaciones de seguridad. Deja de usar la y cambiá al nuevo Nightly. -        \ n \ nPara transferir tus marcadores, inicios de sesión e historial a otra aplicación, creá una cuenta de Firefox. + Esta aplicación ya no va a recibir actualizaciones de seguridad. Dejá de usarla y cambiá al nuevo Nightly. Para transferir tus marcadores, inicios de sesión e historial a otra aplicación, creá una cuenta de Firefox. Cambiá al nuevo Nightly - Firefox Nightly se movió + Firefox Nightly cambió - Esta aplicación ya no va a recibir actualizaciones de seguridad. Deja de usarla y cambiá al nuevo Nightly. -        \ n \ nPara transferir tus marcadores, inicios de sesión e historial a otra aplicación, creá una cuenta de Firefox. + Esta aplicación ya no va a recibir actualizaciones de seguridad. Deja de usarla y cambiá al nuevo Nightly. Para transferir tus marcadores, inicios de sesión e historial a otra aplicación, creá una cuenta de Firefox. Obtené el nuevo Nightly diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index da0a7d115..1ad6ea0e7 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -892,8 +892,6 @@ Automatski briše podatke pregledavanja kad u glavnom izborniku odabereš „Zatvori” Automatski briše podatke pregledavanja kad u glavnom izborniku odabereš „Zatvori” - - Povijest pregledavanja Zatvori @@ -915,8 +913,8 @@ Firefox pregled je sada Firefox Nightly - Firefox Nightly se aktualizira svake večeri i sadrži nove eksperimentalne funkcije. -        Međutim, vjerojatno je manje stabilna verzija. Preuzmi naš beta preglednik za stabilnije iskustvo. + Firefox Nightly je aktualiziran svake noći i sadrži nove eksperimentalne značajke. + Međutim, Nightly može biti manje stabilan. Preuzmi beta verziju našeg preglednika za stabilnije iskustvo. Preuzmite Firefox za Android Beta diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 407ce24fa..1cca008f9 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1107,7 +1107,7 @@ Elementi bloccati nella protezione antitracciamento normale - Restrittivo + Restrittiva Blocca più elementi traccianti, annunci pubblicitari e pop-up. Le pagine verranno caricate più velocemente, ma alcuni elementi potrebbero non funzionare correttamente. diff --git a/app/src/main/res/values-lij/strings.xml b/app/src/main/res/values-lij/strings.xml new file mode 100644 index 000000000..cc1f2c480 --- /dev/null +++ b/app/src/main/res/values-lij/strings.xml @@ -0,0 +1,132 @@ + + + + Privou %s + + %s (Privou) + + + Ciù inpostaçioin + + Abilita Navegaçion privâ + + Dizabilita Navegaçion privâ + + Scrivi ò çerca indirisso + + + No graçie + + + Azonzi widget + + Oua no + + + + Neuvo feuggio + + Neuvo feuggio privou + + I megio sciti + + + + Arvi Feuggi + + Inderê + + + + Agiorna + + Ferma + + Segnalibbro + + Cangia segnalibbro + + Conponenti azonti + + Agiutto + + Cöse gh\'é de neuvo + + Inpostaçioin + + Libraia + + Scito desktop + + Azonzi a-a Pagina Prinçipâ + + Installa + + + + Treuva in pagina + + Feuggio privou + + Neuvo feuggio + + Condividdi + + Condividdi con… + + Arvi in %1$s + + FÆTO CON %1$s + + Tecnologia de %s + + Mòddo letua + + Særa modalitæ letua + + Arvi in app + + Aparensa + + + + Seleçionn-a lengoa + + Çerca + + Deuvia lengoa do dispoxitivo + + Çerca lengoa + + + + Scanscionn-a + + Scorsaiéu + + Çerca con + + Permetti + + No permette + + Atre informaçioin + + + + Çerca + + Çerca inta ræ + + Çerca co-a voxe + + + + Inpostaçioin + + Generale + + diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml new file mode 100644 index 000000000..ebfd9582f --- /dev/null +++ b/app/src/main/res/values-ml/strings.xml @@ -0,0 +1,1383 @@ + + + + + സ്വകാര്യം %s + + %s(സ്വകാര്യം) + + + കൂടുതൽ ഐച്ഛികങ്ങൾ + + സ്വകാര്യ ബ്രൗസിംഗ് സജ്ജമാക്കുക + + സ്വകാര്യ ബ്രൗസിംഗ് നിർജ്ജീവമാക്കുക + + തിരയുക അല്ലെങ്കിൽ വിലാസം നൽകുക + + താങ്കളുടെ തുറന്നു കിടക്കുന്ന ടാബുകൾ ഇവിടെ കാണിക്കും. + + + നിങ്ങളുടെ സ്വകാര്യ ടാബുകൾ ഇവിടെ കാണിക്കും. + + 1 തുറന്നിരിക്കുന്ന ടാബ്. ടാബുകൾ മാറ്റാൻ അമർത്തുക. + + %1$s തുറന്നിരിക്കുന്ന ടാബുകൾ. ടാബുകൾ മാറ്റാൻ ഇത് അമർത്തുക. + + + %1$s നിർമ്മിച്ചത് മോസില്ലയാണ്. + + + + താങ്കൾ ഒരു സ്വകാര്യ സെഷനിലാണ് + + %1$s നിങ്ങളുടെ തിരയലും ബ്രൗസിംഗ് ചരിത്രവും സ്വകാര്യ ടാബുകൾ അടയ്ക്കുമ്പോൾ അല്ലെങ്കിൽ അപ്ലിക്കേഷനിൽ നിന്ന് പുറത്തുകടക്കുമ്പോൾ അവ മായ്‌ക്കുന്നു. ഇത് നിങ്ങളെ വെബ്‌സൈറ്റുകളിലേക്കോ ഇൻറർനെറ്റ് സേവന ദാതാവിലേക്കോ അജ്ഞാതനാക്കില്ലെങ്കിലും, ഈ ഉപകരണം ഉപയോഗിക്കുന്ന മറ്റെതൊരാളിൽ നിന്നും നിങ്ങൾ ഓൺലൈനിൽ ചെയ്യുന്നത് സ്വകാര്യമായി സൂക്ഷിക്കുന്നത് എളുപ്പമാക്കുന്നു. + സ്വകാര്യ ബ്രൗസിങ്ങിനെക്കുറിച്ചുള്ള പൊതുവായ മിഥ്യാധാരണകൾ + + സെഷൻ നീക്കം ചെയ്യുക + + + + നിങ്ങളുടെ ഹോം സ്‌ക്രീനിൽ നിന്ന് സ്വകാര്യ ടാബുകൾ തുറക്കാൻ ഒരു കുറുക്കുവഴി ചേർക്കുക. + + കുറുക്കുവഴി ചേർക്കുക + + വേണ്ട, നന്ദി + + + + ഫയർഫോക്സിലേക്ക് വേഗത്തിൽ എത്തുക. നിങ്ങളുടെ ഹോം സ്‌ക്രീനിൽ ഒരു വിജറ്റ് ചേർക്കുക. + + വിഡ്ജറ്റ് ചേർക്കുക + + ഇപ്പോള്‍ വേണ്ട + + + + പുതിയ ടാബ് + + പുതിയ സ്വകാര്യ ടാബ് + + + പ്രധാന സൈറ്റുകൾ + + + + തുറന്ന ടാബുകള്‍ + + പുറകോട്ട് + + മുന്നോട്ട് + + പുതുക്കുക + + നിർത്തുക + + അടയാളക്കുറിപ്പു് ചേർക്കുക + + അടയാളക്കുറിപ്പ് തിരുത്തുക + + ആഡ്-ഓണുകള്‍ + + ഇവിടെ ആഡ്-ഓണുകളൊന്നുമില്ല + + സഹായം + + പുതിയതെന്തെല്ലാം + + ക്രമീകരണങ്ങള്‍ + + ലൈബ്രറി + + ഡെസ്ക്ടോപ്പ് സൈറ്റ് + + ഹോം സ്ക്രീനിലേക്ക് ചേർക്കുക + + ഇൻസ്റ്റാൾ ചെയ്യുക + + സമന്വയിപ്പിച്ച ടാബുകള്‍ + + പേജിൽ കണ്ടെത്തുക + + സ്വകാര്യ ടാബ് + + പുതിയ ടാബ് + + ശേഖരത്തിലേക്ക് സംരക്ഷിക്കുക + + പങ്കിടുക + + … നോട് പങ്കിടുക + + %1$s ൽ തുറക്കുക + + %1$s ലഭ്യമാക്കുന്നത് + + %1$s ലഭ്യമാക്കുന്നത് + + വായനയ്ക്കുള്ള കാഴ്ച + + വായനയ്ക്കുള്ള കാഴ്ച അടയ്ക്കുക + + ആപ്പിൽ തുറക്കുക + + + ദൃശ്യപരത + + ബന്ധിപ്പിക്കാൻ കഴിയുന്നില്ല. തിരിച്ചറിയാൻ കഴിയാത്ത URL സ്കീം. + + + + തിരഞ്ഞെടുത്ത ഭാഷ + + തിരയുക + + ഉപകരണത്തിന്റെ ഭാഷ തന്നെ ഉപയോഗിക്കുക + + ഭാഷകൾ തിരയുക + + + + സ്കാൻ ചെയ്യുക + + കുറുക്കുവഴികൾ + + തിരച്ചിൽ ക്രമീകരണങ്ങൾ + + ഇതുപയോഗിച്ച് തിരയുക + + ഇത്തവണ ഇതുപയോഗിച്ച് തിരയുക: + + ക്ലിപ്പ്ബോർഡിൽ നിന്ന് കണ്ണി പൂരിപ്പിക്കുക + + അനുവദിക്കുക + + അനുവദിക്കരുത് + + സ്വകാര്യ സെഷനുകളിൽ തിരയൽ നിർദ്ദേശങ്ങൾ അനുവദിക്കണോ? + + നിങ്ങളുടെ സ്ഥിരസ്ഥിതി സെര്‍ച്ച് എഞ്ചിനുമായി വിലാസ ബാറിൽ നിങ്ങൾ എഴുതുന്നതെല്ലാം %s ആയി പങ്കിടും + + കൂടുതല്‍ അറിയുക + + + + തിരയുക + + + വെബിൽ തിരയുക + + ശബ്ദം ഉപയോഗിചു തിരയുക + + + + ക്രമീകരണങ്ങൾ + + അടിസ്ഥാനകാര്യങ്ങൾ + + പൊതുവായവ + + വിവരം + + സ്വതവേയുള്ള സെര്‍ച്ച് എഞ്ചിന്‍ + + തിരയുക + + അഡ്രസ്സ് ബാര്‍ + + സഹായം + + ഗൂഗിൾ പ്ലേയിൽ വിലയിരുത്തുക + + പ്രതികരണം നല്‍കുക + + %1$s നെ കുറിച്ച് + + താങ്കളുടെ അവകാശങ്ങള്‍ + + രഹസ്യവാക്കുകൾ + + ക്രെഡിറ്റ് കാർഡുകളും വിലാസങ്ങളും + + സ്വതേയുള്ള ബ്രൗസര്‍ ആക്കുക + + സങ്കീര്‍ണ്ണമായവ + + സ്വകാര്യത + + സ്വകാര്യതയും സുരക്ഷയും + + സൈറ്റ് അനുമതികൾ + + സ്വകാര്യ ബ്രൗസിങ് + + സ്വകാര്യ ടാബില്‍ കണ്ണികൾ തുറക്കുക + + സ്വകാര്യ ബ്രൗസിങ്ങിൽ സ്‌ക്രീൻഷോട്ടുകൾ അനുവദിക്കുക + + + സ്വകാര്യ ബ്രൗസിംഗ് കുറുക്കുവഴി ചേർക്കുക + + ആക്സസ്സെബിലിറ്റി + + ഇഷ്‌ടാനുസൃത ഫയർഫോക്‌സ് അക്കൗണ്ട് സെർവർ + + ഇഷ്‌ടാനുസൃത സമന്വയ സെർവർ + + ഫയർ‌ഫോക്സ് അകൗണ്ട്/സമന്വയ സെർവർ പരിഷ്‌ക്കരിച്ചു. മാറ്റങ്ങൾ പ്രയോഗിക്കുന്നതിന് അപ്ലിക്കേഷനിൽ നിന്നു പുറത്തുകടക്കുന്നു… + + അക്കൗണ്ട് + + പ്രവേശിക്കുക + + ടൂള്‍ബാര്‍ + + കെട്ടും മട്ടും + + ഇച്ഛാനുസൃതമാക്കുക + + നിങ്ങളുടെ ഫയർഫോക്സ് അക്കൗണ്ട് ഉപയോഗിച്ച് അടയാളക്കുറിപ്പുകളും ചരിത്രവും അങ്ങനെ മറ്റു പലതും സമന്വയിപ്പിക്കുക + + ഫയർഫോക്സ് അക്കൗണ്ട് + + സമന്വയം പുനരാരംഭിക്കുന്നതിന് വീണ്ടും ബന്ധിപ്പിക്കുക + + ഭാഷ + + ഡേറ്റാ ഐച്ഛികങ്ങൾ + + ഡാറ്റ ശേഖരണം + + സ്വകാര്യതാ അറിയിപ്പ് + + ഡെവലപ്പര്‍ ഉപകരണങ്ങള്‍ + + USB വഴിയുള്ള റിമോട്ട് ഡീബഗ്ഗിംഗ് + + തിരയൽ കുറുക്കുവഴികൾ കാണിക്കുക + + തിരയല്‍ നിര്‍ദ്ദേശങ്ങള്‍ കാണിക്കുക + + ശബ്ദം ഉപയോഗിചുള്ള തിരച്ചിൽ കാണിക്കുക + + സ്വകാര്യ സെഷനുകളിൽ കാണിക്കുക + + ക്ലിപ്പ്ബോർഡ് നിര്‍ദ്ദേശങ്ങള്‍ കാണിക്കുക + + ബ്രൗസിങ്ങ് ചരിത്രം തിരയുക + + അടയാളക്കുറിപ്പുകള്‍ തിരയുക + + അക്കൗണ്ട് ക്രമീകരണങ്ങൾ + + ആപ്പുകളിൽ കണ്ണികൾ തുറക്കുക + + ആഡ്-ഓണുകള്‍ + + + + ഇപ്പോൾ സമന്വയിപ്പിക്കുക + + എന്തൊക്കെയാണ് സമന്വയിപ്പിക്കേണ്ടതെന്ന് തിരഞ്ഞെടുക്കുക + + ചരിത്രം + + + അടയാളക്കുറിപ്പുകള്‍ + + ലോഗിനുകൾ + + തുറന്നിരിക്കുന്ന ടാബുകൾ + + പുറത്ത് കടക്കുക + + ഉപകരണത്തിന്റെ പേര് + + ഉപകരണത്തിന്റെ പേര് ശൂന്യമായിരിക്കരുത്. + + സമന്വയിപ്പിക്കുന്നു… + + സമന്വയം പരാജയപ്പെട്ടു. അവസാന വിജയം: %s + + സമന്വയം പരാജയപ്പെട്ടു. അവസാനം സമന്വയിപ്പിച്ചത്: ഒരിക്കലുമില്ല + + അവസാനം സമന്വയിപ്പിച്ചത്: %s + + അവസാനം സമന്വയിപ്പിച്ചത്: ഒരിക്കലുമില്ല + + %2$s %3$s ‍ൽ %1$s + + + + ലഭിച്ച ടാബുകൾ + + മറ്റ് ഫയർഫോക്സ് ഉപകരണങ്ങളിൽ നിന്ന് ലഭിച്ച ടാബുകൾക്കായുള്ള അറിയിപ്പുകൾ. + + ടാബ് ലഭിച്ചു + + ടാബുകൾ ലഭിച്ചു + + %s ല്‍ നിന്നുള്ള ടാബ് + + + + പിന്തുടരൽ സുരക്ഷ + + പിന്തുടരൽ സുരക്ഷ + + താങ്കളെ ഓൺലൈനിൽ പിന്തുടരുന്ന ഉള്ളടക്കവും സ്ക്രിപ്റ്റുകളും തടയുക + + ഒഴിവാക്കലുകള്‍ + + ഈ വെബ്സൈറ്റുകളിൽ പിന്തുടരൽ സുരക്ഷ ഓഫാണ് + + + എല്ലാ സൈറ്റുകൾക്കും ഓണാക്കുക + + തിരഞ്ഞെടുത്ത സൈറ്റുകൾക്കായുള്ള പിന്തുടരൽ പരിരക്ഷ പ്രവർത്തനരഹിതമാക്കാൻ ഒഴിവാക്കലുകൾ താങ്കളെ അനുവദിക്കുന്നു. + + കൂടുതല്‍ അറിയുക + + + ആഗോളതലത്തിൽ ഓഫാക്കി, അത് ഓണാക്കാൻ ക്രമീകരണങ്ങളിലേക്ക് പോകുക. + + + ടെലിമെട്രി + + ഉപയോഗവും സാങ്കേതിക ഡാറ്റയും + + പ്രകടനം, ഉപയോഗം, ഹാർഡ്‌വെയർ തുടങ്ങിയ വിവരങ്ങൾ മോഡില്ലയുമായിമായി പങ്കു വെച്ച് %1$s മെച്ചപ്പെടുത്തുവാൻ സഹായിക്കുക + + വിപണനത്തിനായുള്ള ഡാറ്റ + + %1$sൽ നിങ്ങൾ ഉപയോഗിക്കുന്ന സവിശേഷതകളുമായി ബന്ധപ്പെട്ട ഡാറ്റ ഞങ്ങളുടെ വിപണനസഹായിയായ Leanplumഉമായി പങ്കുവെയ്ക്കുന്നു. + + പരീക്ഷണങ്ങള്‍ + + പരീക്ഷണാത്മക സവിശേഷതകൾക്കായി ഇൻസ്റ്റാൾ ചെയ്യാനും ഡാറ്റ ശേഖരിക്കാനും മോസില്ലയെ അനുവദിക്കുന്നു + + തകരാർ റിപ്പോർട്ടർ + + മോസില്ല ലൊക്കേഷൻ സേവനം + + %s ആരോഗ്യ റിപ്പോർട്ട് + + + + സിങ്ക് ഓണാക്കുക + + ഡെസ്ക്ടോപ്പ് ഫയർഫോക്സിൽ ജോടിയാക്കൽ കോഡ് സ്കാൻ ചെയ്യുക + + പ്രവേശിക്കുക + + വീണ്ടും ബന്ധിപ്പിക്കുന്നതിന് പ്രവേശിക്കുക + + അക്കൗണ്ട് നീക്കം ചെയ്യുക + + + + firefox.com/pair ൽ കാണിച്ചിരിക്കുന്ന QR കോഡ് സ്കാൻ ചെയ്യുക]]> + + ക്യാമറ തുറക്കുക + + റദ്ദാക്കുക + + + + മുകളിൽ + + താഴെ + + + + ഇളം + + കടും + + + ബാറ്ററി സേവർ സജ്ജമാക്കിയത് + + ഉപകരണ തീം പിന്തുടരുക + + + + സെഷനുകൾ + + സ്ക്രീൻഷോട്ടുകൾ + + ഡൗണ്‍ലോഡുകള്‍ + + അടയാളക്കുറിപ്പുകള്‍ + + ഡെസ്ക്ടോപ്പ് അടയാളക്കുറിപ്പുകള്‍ + + അടയാളക്കുറിപ്പുകളുടെ മെനു + + അടയാളക്കുറിപ്പിനുള്ള ടൂള്‍ബാര്‍ + + മറ്റു് അടയാളക്കുറിപ്പുകള്‍ + + ചരിത്രം + + സമന്വയിപ്പിച്ച ടാബുകള്‍ + + വായനാ പട്ടിക + + + തിരയുക + + ക്രമീകരണങ്ങള്‍ + + ചരിത്ര ഇന മെനു + + അടയ്ക്കുക + + + + തുറന്നിരുന്ന ടാബുകള്‍ + + സ്വകാര്യ സെഷൻ + + സ്വകാര്യ ടാബുകൾ + + + ടാബ് ചേര്‍ക്കുക + + സ്വകാര്യ ടാബ് ചേർക്കുക + + സ്വകാര്യം + + തുറന്നിരിക്കുന്ന ടാബുകള്‍ + + ശേഖരത്തിലേക്ക് സംരക്ഷിക്കുക + + എല്ലാ ടാബുകളും പങ്കിടുക + + എല്ലാ ടാബുകളും അടയ്ക്കുക + + പുതിയ ടാബ് + + പൂമുഖത്തേയ്ക്കു് പോകുക + + ടാബ് രീതി മാറ്റുക + + ശേഖരത്തിൽ നിന്ന് ടാബ് നീക്കം ചെയ്യുക + + ടാബ് അടയ്ക്കുക + + %s ടാബ് അടയ്ക്കുക + + ടാബുകളുടെ മെനു തുറക്കുക + + എല്ലാ ടാബുകളും അടയ്ക്കുക + + ടാബുകൾ പങ്കിടുക + + ശേഖരത്തിലേക്ക് ടാബുകൾ സംരക്ഷിക്കുക + + ടാബ് മെനു + + ടാബ് പങ്കിടുക + + നീക്കം ചെയ്യുക + + സംരക്ഷിക്കുക + + പങ്കിടുക + + നിലവിലെ സെഷൻ ചിത്രം + + ശേഖരത്തിലേക്ക് സംരക്ഷിക്കുക + + ശേഖരം നീക്കം ചെയ്യുക + + ശേഖരത്തിന്റെ പേരുമാറ്റുക + + ടാബുകള്‍ തുറക്കുക + + നീക്കം ചെയ്യുക + + %1$s (സ്വകാര്യ രീതി) + + + + നാള്‍വഴികൾ ഇല്ലാതാക്കുക + + നിങ്ങളുടെ നാൾവഴികൾ മായിക്കാൻ നിങ്ങൾക്ക് സമ്മതമാണോ? + + ചരിത്രം ഇല്ലാതാക്കി + + %1$s നീക്കം ചെയ്തു + + മായ്ക്കുക + + പകര്‍ത്തുക + + പങ്കിടുക + + പുതിയ ടാബില്‍ തുറക്കുക + + സ്വകാര്യ ടാബിൽ തുറക്കുക + + നീക്കം ചെയ്യുക + + %1$d തിരഞ്ഞെടുത്തിരിക്കുന്നു + + %1$d ഇനങ്ങൾ ഇല്ലാതാക്കുക + + കഴിഞ്ഞ 24 മണിക്കൂര്‍ + + കഴിഞ്ഞ 7 ദിവസം + + കഴിഞ്ഞ 30 ദിവസം + + പഴയത് + + + ഇവിടെ ചരിത്രമൊന്നുമില്ല + + + + ക്ഷമിക്കണം. %1$s ന് ആ പേജ് ലഭ്യമാക്കാൻ കഴിഞ്ഞില്ല. + + താങ്കൾക്ക് ചുവടെയുള്ള ഈ ടാബ് പുനഃസ്ഥാപിക്കാൻ ശ്രമിക്കുകയോ അടയ്ക്കുകയോ ചെയ്യാം. + + തകരാർ റിപ്പോ‍ർട്ട് മോസില്ലയിലേക്ക് അയയ്ക്കുക + + ടാബ് അടയ്ക്കുക + + + ടാബ് പുനസ്ഥാപിക്കുക + + + സെഷൻ ഐച്ഛികങ്ങൾ + + + സെഷൻ പങ്കിടുക + + + + അടയാളക്കുറിപ്പുകള്‍ + + അടയാളക്കുറിപ്പ് തിരുത്തുക + + ഫോൾഡർ തിരഞ്ഞെടുക്കുക + + ഈ ഫോൾഡർ നീക്കം ചെയ്യണമെന്ന് താങ്കൾക്ക് ഉറപ്പാണോ? + + %1$s നീക്കം ചെയ്തു + + ഫോൾഡർ ചേർക്കുക + + + അടയാളക്കുറിപ്പ് സൃഷ്ടിച്ചു. + + അടയാളക്കുറിപ്പ് സൂക്ഷിച്ചു! + + തിരുത്തുക + + തിരുത്തുക + + തിരഞ്ഞെടുക്കുക + + പകര്‍ത്തുക + + പങ്കിടുക + + പുതിയ ടാബില്‍ തുറക്കുക + + സ്വകാര്യ ടാബിൽ തുറക്കുക + + നീക്കം ചെയ്യുക + + സൂക്ഷിക്കുക + + %1$d തിരഞ്ഞെടുത്തു + + അടയാളക്കുറിപ്പ് തിരുത്തുക + + ഫോള്‍ഡര്‍ തിരുത്തുക + + സമന്വയിപ്പിച്ച ബുക്ക്മാർക്കുകൾ കാണാൻ പ്രവേശിക്കുക + + URL + + ഫോൾഡർ + + പേര് + + ഫോൾഡർ ചേർക്കുക + + ഫോൾഡർ തിരഞ്ഞെടുക്കുക + + നിർബന്ധമായും ഒരു ശീർഷകം ഉണ്ടായിരിക്കണം + + URL അസാധുവാണ് + + അടയാളക്കുറിപ്പുകളൊന്നുമില്ല + + %1$s നീക്കം ചെയ്തു + + അടയാളക്കുറിപ്പുകൾ നീക്കം ചെയ്തു + + പൂർവസ്ഥിതിയാക്കുക + + + + അനുമതികൾ + + സജ്ജീകരണങ്ങളിലേക്കു പോവുക + + ദ്രുത ക്രമീകരണ ഷീറ്റ് + + ശുപാർശ ചെയ്തത് + + സൈറ്റ് അനുമതികൾ നിയന്ത്രിക്കുക + + അനുമതികൾ ഇല്ലാതാക്കുക + + അനുമതി ഇല്ലാതാക്കുക + + എല്ലാ സൈറ്റുകളിലെയും അനുമതികൾ ഇല്ലാതാക്കുക + + ഓട്ടോപ്ലേ + + ക്യാമറ + + മൈക്രോഫോണ്‍ + + സ്ഥലവിവരം + + അറിയിപ്പ് + + അനുവദിക്കാൻ ആവശ്യപ്പെടുക + + തടഞ്ഞവ + + അനുവദനീയം + + ആൻഡ്രോയിഡ് തടഞ്ഞു + + വിട്ടുവീഴ്ചകള്‍ + + ഓണ്‍ + + + ഓഫ് + + ഓഡിയോയും വീഡിയോയും അനുവദിക്കുക + + സെല്ലുലാർ ഡാറ്റയിൽ മാത്രം ഓഡിയോയും വീഡിയോയും തടയുക + + ഓഡിയോയും വീഡിയോയും വൈഫൈയിൽ പ്രവർത്തിക്കും + + ശബ്ദം മാത്രം തടയുക + + ഓഡിയോയും വീഡിയോയും തടയുക + + ഓണ്‍ + + ഓഫ് + + + + ശേഖരങ്ങൾ + + ശേഖരണ മെനു + + നിങ്ങൾക്ക് പ്രാധാന്യമുള്ള കാര്യങ്ങൾ ശേഖരിക്കുക + + അതിവേഗ ഉപയോഗത്തിനായി സമാന തിരയലുകൾ, സൈറ്റുകൾ, ടാബുകൾ എന്നിവ ഒരുമിച്ച് ചേർക്കുക. + + ടാബുകൾ തിരഞ്ഞെടുക്കുക + + ശേഖരം തിരഞ്ഞെടുക്കുക + + ശേഖരത്തിന് പേരിടുക + + പുതിയ ശേഖരം ചേർക്കുക + + എല്ലാം തിരഞ്ഞെടുക്കുക + + തിരഞ്ഞെടുത്തവ വേണ്ടെന്ന് വയ്ക്കുക + + സംരക്ഷിക്കേണ്ട ടാബുകൾ തിരഞ്ഞെടുക്കുക + + %d ടാബുകൾ തിരഞ്ഞെടുത്തു + + %d ടാബ് തിരഞ്ഞെടുത്തു + + ടാബുകൾ സൂക്ഷിച്ചു! + + ടാബ് സൂക്ഷിച്ചു! + + അടയ്ക്കുക + + സൂക്ഷിക്കുക + + കാണുക + + + %d ശേഖരം + + + + അയച്ച് പങ്കിടുക + + പങ്കിടുക + + പങ്കിടുക + + ഒരു കണ്ണി പങ്കിടുക + + ഉപകരണത്തിലേക്ക് അയക്കു + + എല്ലാ പ്രവർത്തനങ്ങളും + + സമീപകാലത്ത് ഉപയോഗിച്ചവ + + സമന്വയിപ്പിക്കാനായി പ്രവേശിക്കുക + + എല്ലാ ഉപകരണങ്ങളിലേക്കും അയയ്ക്കുക + + സമന്വയിക്കാൻ വീണ്ടും ബന്ധിപ്പിക്കുക + + ഓഫ്‌ലൈൻ + + മറ്റൊരു ഉപകരണം ബന്ധിപ്പിക്കുക + + ഒരു ടാബ് അയയ്‌ക്കാൻ, മറ്റ് ഒരു ഉപകരണത്തിലെങ്കിലും ഫയർഫോക്‌സിൽ പ്രവേശിക്കുക. + + മനസ്സിലായി + + ഈ ആപ്പിലേക്ക് പങ്കിടാൻ സാധിക്കില്ല + + ഉപകരണത്തിലേക്ക് അയക്കു + + ഉപകരണങ്ങളൊന്നും ബന്ധിപ്പിച്ചിട്ടില്ല + + ടാബുകൾ അയയ്ക്കുന്നതിനെക്കുറിച്ച് അറിയുക… + + മറ്റൊരു ഉപകരണം ബന്ധിപ്പിക്കുക… + + + + സ്വകാര്യ ബ്രൗസിങ് സെഷൻ + + സ്വകാര്യ ടാബുകൾ നീക്കം ചെയ്യുക + + സ്വകാര്യ ടാബുകള്‍ അടയ്ക്കുക + + തുറക്കുക + + നീക്കം ചെയ്തിട്ട് തുറക്കുക + + അവതരിപ്പിക്കുന്നത് + + ശേഖരം ഇല്ലാതാക്കി + + ശേഖരത്തിന്റെ പേരുമാറ്റി + + ടാബ് നീക്കം ചെയ്തു + + ടാബുകൾ നീക്കം ചെയ്തു + + ടാബ് അടച്ചു + + + ടാബുകൾ അടച്ചു + + മികച്ച സൈറ്റുകളിൽ ചേർത്തു! + + സ്വകാര്യ ടാബ് അടച്ചു + + സ്വകാര്യ ടാബുകൾ അടച്ചു + + സ്വകാര്യ ടാബുകൾ നീക്കം ചെയ്തു + + തിരിച്ചാക്കുക + + സൈറ്റ് നീക്കം ചെയ്തു + + തിരിച്ചാക്കുക + + സ്ഥിരീകരിക്കുക + + %2$s തുറക്കാൻ %1$s നെ അനുവദിക്കുക + + അനുവദിക്കുക + + നിരസിക്കുക + + %1$s നീക്കം ചെയ്യണമെന്ന് താങ്കൾക്ക് ഉറപ്പാണോ? + + നീക്കം ചെയ്യുക + + റദ്ദാക്കുക + + സ്ക്രീൻ പൂര്‍ണ്ണവലിപ്പത്തിലാക്കുന്നു + + URL പകർത്തി + + ഇതൊരു ഉദാഹരണ വാചകമാണ്. നിങ്ങൾ അക്ഷരത്തിന്റെ വലുപ്പം കൂട്ടുകയോ കുറയ്ക്കുകയോ ചെയ്യുമ്പോൾ എങ്ങനെ ദൃശ്യമാകുമെന്ന് കാണിക്കാൻ ഇത് സഹായിക്കുന്നു. + + വെബ്സൈറ്റുകളിലെ അക്ഷരങ്ങൾ വലുതോ ചെറുതോ ആക്കുക + + ഫോണ്ട് വലുപ്പം + + + ഫോണ്ടിന്റെ വലുപ്പത്തിന്റെ യാന്ത്രിക ക്രമീകരണം + + ഫോണ്ട് വലുപ്പം നിങ്ങളുടെ Android ക്രമീകരണങ്ങളുമായി പൊരുത്തപ്പെടും. ഫോണ്ട് വലുപ്പം ഇവിടെ നിയന്ത്രിക്കുന്നത് നിർജ്ജീവമാക്കുക. + + + ബ്രൗസിങ്ങ് ഡാറ്റ നീക്കം ചെയ്യുക + + ടാബുകൾ തുറക്കുക + + %d ടാബുകL + + + ബ്രൗസിങ്ങ് ചരിത്രവും സൈറ്റ് ഡാറ്റയും + + %d വിലാസങ്ങൾ + + ചരിത്രം + + %d പേജുകൾ + + കുക്കികള്‍ + + മിക്ക സൈറ്റുകളിൽ നിന്നും നിങ്ങൾ പുറത്തിറങ്ങും + + ക്യാഷ് ചെയ്ത ചിത്രങ്ങളും ഫയലുകളും + + സംഭരണ ഇടം വൃത്തിയാക്കുന്നു + + സൈറ്റ് അനുമതികൾ + + ബ്രൗസിങ്ങ് ഡാറ്റ നീക്കം ചെയ്യുക + + പുറത്ത് കടക്കുമ്പോൾ ബ്രൗസിങ്ങ് ഡാറ്റ നീക്കം ചെയ്യുക + + പ്രധാന മെനുവിൽ നിന്ന് "പുറത്തുകടക്കുക" തിരഞ്ഞെടുക്കുമ്പോൾ ബ്രൗസിംഗ് ഡാറ്റ തനിയേ നീക്കം ചെയ്യുന്നു + + പ്രധാന മെനുവിൽ നിന്ന് \"പുറത്തുകടക്കുക\" തിരഞ്ഞെടുക്കുമ്പോൾ ബ്രൗസിംഗ് ഡാറ്റ തനിയേ നീക്കം ചെയ്യുന്നു + + പുറത്ത് കടക്കുക + + + ഇത് താങ്കളുടെ എല്ലാ ബ്രൗസിങ്ങ് ഡാറ്റയും നീക്കം ചെയ്യും + + %s തിരഞ്ഞെടുത്ത ബ്രൗസിങ്ങ് ഡാറ്റ നീക്കം ചെയ്യും. + + റദ്ദാക്കുക + + നീക്കം ചെയ്യുക + + ബ്രൗസിംഗ് ഡാറ്റ നീക്കം ചെയ്തു + + ബ്രൗസിംഗ് ഡാറ്റ നീക്കം ചെയ്യുന്നു… + + + + ഫയർഫോക്സ് പ്രിവ്യൂ ഇപ്പോൾ ഫയർഫോക്സ് നൈറ്റ്‌ലി ആണ് + + + ഫയർഫോക്സ് നൈറ്റ്ലി എല്ലാ ദിവസവും രാത്രി അപ്ഡേറ്റ് ആവുകയും പരീക്ഷണാത്മക സവിശേഷതകൾ നേടുകയും ചെയ്യുന്നു. + എന്നിരുന്നാലും, ഇതിന് സ്ഥിരത കുറവായേക്കാം. നല്ല സ്ഥിരതയുള്ള അനുഭവത്തിനായി ഞങ്ങളുടെ ബീറ്റാ ബ്രൗസർ ഡൗൺലോഡ് ചെയ്യുക. + + ആൻഡ്രോയിഡിനായുള്ള ഫയർഫോക്സ് ബീറ്റ നേടുക + + + ഫയർഫോക്സ് നൈറ്റ്ലി മാറിയിരിക്കുന്നു + + ഈ ആപ്പിന് ഇനി സുരക്ഷാ പുതുക്കലുകൾ ലഭിക്കില്ല. ഈ ആപ്പ് ഉപയോഗിക്കുന്നത് നിർത്തി പുതിയ നൈറ്റ്ലിയിലേക്ക് മാറുക. + \n\nതാങ്കളുടെ അടയാളക്കുറിപ്പുകളും, ലോഗിനുകളും ചരിത്രവും മറ്റൊരു ആപ്പിലേക്ക് കൈമാറാൻ, ഒരു ഫയർഫോക്സ് അക്കൗണ്ട് സൃഷ്ടിക്കുക. + + പുതിയ നൈറ്റ്ലിയിലേക്ക് മാറുക + + + ഫയർഫോക്സ് നൈറ്റ്ലി മാറിയിരിക്കുന്നു + + .ഈ അപ്ലിക്കേഷന് ഇനി സുരക്ഷാ അപ്‌ഡേറ്റുകൾ ലഭിക്കില്ല. ഈ അപ്ലിക്കേഷൻ ഉപയോഗിക്കുന്നത് നിർത്തി പുതിയ നൈറ്റ്ലിയിലേക്ക് മാറുക. +· \n\n നിങ്ങളുടെ ബുക്ക്മാർക്കുകളും ലോഗിനുകളും ചരിത്രവും മറ്റൊരു അപ്ലിക്കേഷനിലേക്ക് കൈമാറാൻ, ഒരു ഫയർഫോക്സ് അക്കൗണ്ട് സൃഷ്ടിക്കുക. + + പുതിയ നൈറ്റ്ലി നേടുക + + + + %s ലേക്ക് സ്വാഗതം! + + നിലവിൽ അക്കൗണ്ട് ഉണ്ടോ? + + %s നെ പറ്റി അറിയുക + + പുതിയതെന്താണെന്ന് കാണുക + + പുനർ‌രൂപകൽപ്പന ചെയ്‌ത %sനെക്കുറിച്ച് ചോദ്യങ്ങളുണ്ടോ? എന്താണ് മാറിയതെന്ന് അറിയണോ? + + ഉത്തരങ്ങൾ ഇവിടെ നേടുക + + %s പരമാവധി പ്രയോജനപ്പെടുത്തുക. + + ഈ ഫോണിലെ മറ്റൊരു ഫയർ‌ഫോക്സ് ബ്രൗസറിൽ‌ നിങ്ങൾ‌ %s ആയി പ്രവേശിച്ചു. ഈ അക്കൗണ്ട് ഉപയോഗിച്ച് പ്രവേശിക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ? + + ഉവ്വ, പ്രവേശിക്കുക + + പ്രവേശിക്കുന്നു… + + ഫയര്‍ഫോക്സിലേക്ക് പ്രവേശിക്കുക + + പുറത്തിറങ്ങിയതായി തുടരുക + + സിങ്ക് ഓണാണ് + + പ്രവേശിക്കുന്നതിൽ പരാജയപ്പെട്ടു + + സ്വതവേയുള്ള സ്വകാര്യത + + സ്വകാര്യത, സുരക്ഷാ ക്രമീകരണങ്ങൾ താങ്കളെ പിന്തുടരുന്ന ട്രാക്കറുകൾ, മാൽവെയർ, കമ്പനികൾ എന്നിവയെ തടയുന്നു. + + സ്റ്റാൻഡേർഡ് (തനതായിട്ടുള്ളത്) + + കുറച്ച് ട്രാക്കറുകളെ തടയുന്നു. പേജുകൾ സാധാരണ പോലെ ലഭ്യമാവും. + + കർശനം (ശുപാർശചെയ്യുന്നു) + + കർശനം + + കൂടുതൽ ട്രാക്കറുകൾ, പരസ്യങ്ങൾ, പോപ്പ്അപ്പുകൾ എന്നിവ തടയുന്നു. പേജുകൾ വേഗത്തിൽ ലോഡുചെയ്യുന്നു, പക്ഷേ ചില പ്രവർത്തനങ്ങൾ ലഭ്യമായിരിക്കില്ല. + + ഒരു നിലപാട് എടുക്കുക + + ചുവടെയുള്ള ടൂൾബാർ ഉപയോഗിച്ച് ഒറ്റ കൈ ബ്രൗസിംഗ് പരീക്ഷിക്കുക അല്ലെങ്കിൽ മുകളിലേക്ക് നീക്കുക. + + സ്വകാര്യമായി ബ്രൗസ് ചെയ്യുക + + ഒരു സ്വകാര്യ ടാബ് ഒരിക്കൽ തുറക്കുക: %s ഐക്കൺ അമർത്തുക. + + എല്ലാ സമയത്തും സ്വകാര്യ ടാബുകൾ തുറക്കുക: നിങ്ങളുടെ സ്വകാര്യ ബ്രൗസിംഗ് ക്രമീകരണങ്ങൾ പുനക്രമീകരിക്കുക. + + ക്രമീകരണങ്ങൾ തുറക്കുക + + താങ്കളുടെ സ്വകാര്യത + + ഞങ്ങളുടെ സ്വകാര്യതാ അറിയിപ്പ് വായിക്കുക + + അടയ്ക്കുക + + + ബ്രൗസിങ് തുടങ്ങൂക + + + + കെട്ടും മട്ടും തിരഞ്ഞെടുക്കുക + + + ഇരുണ്ട മോഡ് പ്രവർത്തനക്ഷമമാക്കുന്നതിലൂടെ കാഴ്ചശക്തിയും ബാറ്ററിയും സംരക്ഷിക്കുക. + + സ്വയം + + നിങ്ങളുടെ ഉപകരണത്തിന്റെ ക്രമീകരണം പിൻതുടരുന്നു + + ഇരുണ്ട തീം + + + ലൈറ്റ് തീം + + + ടാബുകൾ അയച്ചു! + + ടാബ് അയച്ചു! + + അയയ്ക്കാനായില്ല + + വീണ്ടും ശ്രമിക്കുക + + കോഡ് സ്കാൻ ചെയ്യുക + + https://firefox.com/pair എന്നതിലേക്ക് പോകുക]]> + + സ്കാൻ ചെയ്യാൻ തയ്യാറാണ് + + താങ്കളുടെ ക്യാമറ ഉപയോഗിച്ച് പ്രവേശിക്കുക + + പകരം ഇമെയിൽ ഉപയോഗിക്കുക + + + താങ്കളുടെ അക്കൗണ്ടുമായി സമന്വയിപ്പിക്കുന്നത് ഫയർഫോക്സ് നിർത്തും പക്ഷേ ഈ ഉപകരണത്തിലുള്ള താങ്കളുടെ ബ്രൗസിങ്ങ് ഡാറ്റയൊന്നും നീക്കം ചെയ്യില്ല. + + താങ്കളുടെ അക്കൗണ്ടുമായി സമന്വയിപ്പിക്കുന്നത് %s നിർത്തും പക്ഷേ ഈ ഉപകരണത്തിലുള്ള താങ്കളുടെ ബ്രൗസിങ്ങ് ഡാറ്റയൊന്നും നീക്കം ചെയ്യില്ല. + + വിച്ഛേദിക്കുക + + റദ്ദാക്കുക + + + തനതു ഫോള്‍ഡറുകൾ എഡിറ്റ് ചെയ്യാൻ കഴിയില്ല + + + + പരിരക്ഷാ ക്രമീകരണങ്ങൾ + + മെച്ചപ്പെട്ട ട്രാക്കിംഗ് പരിരക്ഷണം + + പിന്തുടരപ്പെടാതെ ബ്രൗസുചെയ്യുക + + കൂടുതല്‍ അറിയുക + + + സ്റ്റാൻഡേർഡ് (തനതായിട്ടുള്ളത്) + + കുറച്ച് ട്രാക്കറുകൾ തടയുന്നു. പേജുകൾ സാധാരണ പോലെ ലോഡുചെയ്യും. + + സ്റ്റാൻഡേർഡ് ട്രാക്കിംഗ് പരിരക്ഷണം എന്തെല്ലാം തടഞ്ഞു + + കർശനം + + ഇച്ഛാനുസൃതം + + + കുക്കികള്‍ + + സന്ദർശിക്കാത്ത സൈറ്റുകളിൽ നിന്നുള്ള കുക്കികൾ + + + എല്ലാ ടാബുകളിലും + + സ്വകാര്യ ടാബുകളിൽ മാത്രം + + ഇച്ഛാനുസൃത ടാബുകളിൽ മാത്രം + + വിരലടയാളങ്ങൾ + തടഞ്ഞവ + + അനുവദിച്ചത് + + സമൂഹ മാധ്യമ ട്രാക്കറുകൾ + + വിരലടയാളങ്ങൾ + + പിന്തുടരുന്ന ഉള്ളടക്കം + + ഈ സൈറ്റിനായി പരിരക്ഷകൾ ഓണാണ് + + ഈ സൈറ്റിനായി പരിരക്ഷകൾ ഓഫാണ് + + ഈ വെബ്സൈറ്റുകളിൽ അധിക പിന്തുടരൽ സുരക്ഷ ഓഫാണ് + + പുറകോട്ട് പോവുക + + താങ്കളുടെ അവകാശങ്ങള്‍ + + ഞങ്ങൾ ഉപയോഗിക്കുന്ന ഓപ്പൺ സോഴ്‌സ് ലൈബ്രറികൾ + + %s- ൽ പുതിയതെന്താണ് + + %s| സ്വതന്ത്ര ലൈബ്രറികൾ + + + പിന്തുണ + + തകരാറുകള്‍ + + സ്വകാര്യതാ അറിയിപ്പ് + + നിങ്ങളുടെ അവകാശങ്ങള്‍ അറിയുക + + ലൈസന്‍സ് വിവരം + + ഞങ്ങൾ ഉപയോഗിക്കുന്ന ലൈബ്രറികൾ + ഡീബഗ് മെനു പ്രവർത്തനക്ഷമമാക്കി + + + 1 ടാബ് + + %d ടാബുകൾ + + + + പകര്‍ത്തുക + + പകർത്തി തുടരുക + + പതിക്കുക + + URL ക്ലിപ്ബോർഡിലേക്ക് പകർത്തി + + + ഹോം സ്‌ക്രീനിലേക്ക് ചേർക്കുക + + റദ്ദാക്കുക + + ചേർക്കൂ + + വെബ്‌സൈറ്റിലേക്ക് തുടരുക + + കുറുക്കുവഴിയുടെ പേര് + + + ലോഗിനുകളും പാസ്‌വേഡുകളും + + ലോഗിനുകളും പാസ്‌വേഡുകളും സംരക്ഷിക്കുക + + സൂക്ഷിക്കാൻ ആവശ്യപ്പെടുക + + ഒരിക്കലും സൂക്ഷിക്കേണ്ട + + സ്വയം പൂരിപ്പിക്കുക + + ലോഗിനുകൾ സമന്വയിപ്പിക്കുക + + ഓണ്‍ + + ഓഫ് + + വീണ്ടും ബന്ധിപ്പിക്കുക + + സമന്വയിപ്പിക്കാനായി പ്രവേശിക്കുക + + സൂക്ഷിച്ചിട്ടുള്ള പ്രവേശനങ്ങള്‍ + + നിങ്ങൾ സംരക്ഷിച്ച അല്ലെങ്കിൽ %s ലേക്ക് സമന്വയിപ്പിക്കുന്ന ലോഗിനുകൾ ഇവിടെ ദൃശ്യമാകും. + + സമന്വയത്തെ കുറിച്ച് കൂടുതല്‍ മനസ്സിലാക്കുക. + + വിട്ടുവീഴ്ചകള്‍ + + സംരക്ഷിക്കാത്ത ലോഗിനുകളും രഹസ്യവാക്കുകളും ഇവിടെ കാണിക്കും. + + ഈ സൈറ്റുകൾക്കായി ലോഗിനുകളും രഹസ്യവാക്കുകളും സംരക്ഷിക്കില്ല. + + ലോഗിനുകളിൽ തിരയുക + + അക്ഷരമാലാക്രമത്തില്‍ + + സമീപകാലത്ത് ഉപയോഗിച്ചവ + + സൈറ്റ്‌ + + ഉപയോക്തൃനാമം + + രഹസ്യവാക്ക് + + നിങ്ങളുടെ പിൻ വീണ്ടും നൽകുക + + നിങ്ങളുടെ സംരക്ഷിച്ച ലോഗിനുകൾ കാണാൻ അൺലോക്കുചെയ്യുക + + ഈ ബന്ധം സുരക്ഷിതമല്ല. ഇവിടെ നല്‍കിയ പ്രവേശനങ്ങളിൽ വിട്ടുവീഴ്ചകള്‍ ഉണ്ടായിട്ടുണ്ടാകാം + + കൂടുതല്‍ അറിയുക + + താങ്കൾക്ക് %s ഈ ലോഗിൻ സംരക്ഷിക്കണമെന്നുണ്ടോ? + + സംരക്ഷിക്കുക + + സംരക്ഷിക്കേണ്ട + + ക്ലിപ്പ്ബോര്‍ഡിലേക്കു് രഹസ്യവാക്ക് പകര്‍ത്തി + + ഉപയോക്തൃനാമം ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തി + + സൈറ്റ് ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തിയിരിക്കുന്നു + + രഹസ്യവാക്ക് പകര്‍ത്തുക + + ഉപയോക്തൃനാമം പകര്‍ത്തുക + + സൈറ്റ് പകർത്തുക + + രഹസ്യവാക്ക് കാണിക്കുക + + രഹസ്യവാക്ക് മറയ്ക്കുക + + നിങ്ങളുടെ സംരക്ഷിച്ച ലോഗിനുകൾ കാണാൻ അൺലോക്കുചെയ്യുക + + നിങ്ങളുടെ ലോഗിനുകളും രഹസ്യവാക്കുകളും സുരക്ഷിതമാക്കുക + + പിന്നീട് + + ഇപ്പോൾ സജ്ജമാക്കുക + + താങ്കളുടെ ഉപകരണത്തിന്റെ പൂട്ട് തുറക്കുക + + എല്ലാ വെബ്‌സൈറ്റുകളിലും സൂം ചെയ്യുക + + + പേര് (A-Z) + + അവസാനം ഉപയോഗിച്ചത് + + ലോഗിൻ മെനു അടുക്കുക + + + തിരച്ചിൽ യന്ത്രം ചേർക്കുക + + തിരച്ചിൽ എഞ്ചിൻ തിരുത്തുക + + ചേർക്കുക + + സൂക്ഷിക്കുക + + തിരുത്തുക + + നീക്കം ചെയ്യുക + + + മറ്റുള്ളവ + + പേര് + + തിരയാനുള്ള വാചകം + + കൂടുതല്‍ അറിയുക + + + ഇഷ്‌ടാനുസൃത തിരച്ചിൽ എഞ്ചിന്റെ വിശദാംശങ്ങൾ + + കൂടുതലറിയാനുള്ള കണ്ണി + + + തിരച്ചിൽ എഞ്ചിൻ പേര് നൽകുക + + “%s” എന്ന പേരിലുള്ള തിരച്ചിൽ എഞ്ചിൻ ഇതിനകം നിലവിലുണ്ട്. + + തിരയുന്നതിനായി ഒരു വാചകം നൽകുക + + “%s” ലേക്ക് ബന്ധിപ്പിക്കന്നതിൽ പിശക് + + %s സൃഷ്ടിച്ചു + + %s സൂക്ഷിച്ചു + + %s നീക്കം ചെയ്തു + + + ഏറ്റവും നവീനമായ %s ലേക്ക് സ്വാഗതം + + %s പുതുക്കുന്നു… + + %s തുടങ്ങുക + + രഹസ്യവാക്കുകൾ + + + ഇത് അനുവദിക്കുന്നതിന്: + + + 1. ആൻഡ്രോയിഡ് ക്രമീകരണങ്ങളിലേക്ക് പോകുക + + അനുമതികൾ അമർത്തുക]]> + + %1$s ഓണാക്കുക]]> + + + സുരക്ഷിത കണക്ഷന്‍ + + സുരക്ഷിതമല്ലാത്ത കണക്ഷന്‍ + + എല്ലാ സൈറ്റുകളിലെയും എല്ലാ അനുമതികളും മായ്‌ക്കണമെന്ന് താങ്കൾക്ക് ഉറപ്പാണോ? + + ഈ സൈറ്റിനായുള്ള എല്ലാ അനുമതികളും മായ്‌ക്കണമെന്ന് താങ്കൾക്ക് ഉറപ്പാണോ? + + ഈ സൈറ്റിനായുള്ള ഈ അനുമതി മായ്‌ക്കണമെന്ന് താങ്കൾക്ക് ഉറപ്പാണോ? + + സൈറ്റ് ഒഴിവാക്കലുകളൊന്നുമില്ല + + മികച്ച ലേഖനങ്ങൾ + + ഈ അടയാളക്കുറിപ്പ് നീക്കം ചെയ്യണമെന്ന് താങ്കൾക്ക് ഉറപ്പാണോ? + + മികച്ച സൈറ്റുകളിലേക്ക് ചേർക്കുക + + പരിശോധിച്ചത്: %1$s + + നീക്കം ചെയ്യുക + + തിരുത്തുക + + ഈ ലോഗിൻ നീക്കം ചെയ്യണമെന്ന് താങ്കൾക്ക് ഉറപ്പാണോ? + + നീക്കം ചെയ്യുക + + ലോഗിൻ ഐച്ഛികങ്ങൾ + + ലോഗിനിന്റെ വെബ് വിലാസത്തിനായുള്ള തിരുത്താനാകുന്ന ടെക്സ്റ്റ് ഫീൽഡ്. + + ലോഗിനിന്റെ ഉപയോക്തൃനാമത്തിനായുള്ള തിരുത്താനാകുന്ന ടെക്സ്റ്റ് ഫീൽഡ്. + + ലോഗിനിന്റെ രഹസ്യവാക്കിനായുള്ള തിരുത്താനാകുന്ന ടെക്സ്റ്റ് ഫീൽഡ്. + + ലോഗിനിലുള്ള മാറ്റങ്ങൾ സംരക്ഷിക്കുക. + + മാറ്റങ്ങൾ ഉപേക്ഷിക്കുക + + തിരുത്തുക + + രഹസ്യവാക്ക് ആവശ്യമാണു് + + ശബ്ദം ഉപയോഗിചു് തിരയുക + + ഇപ്പോള്‍ സംസാരിക്കൂ + + അതെ പേരിൽ മറ്റൊരു ഉപയോക്താവ് നിലവിലുണ്ട് + + + + ഫയർഫോക്സ് അക്കൗണ്ടുമായി ബന്ധിപ്പിക്കുക. + + മറ്റൊരു ഉപകരണം ബന്ധിപ്പിക്കുക. + + ദയവായി പുനഃപ്രമാണീകരിക്കുക + + ടാബ് സമന്വയിപ്പിക്കൽ പ്രാപ്തമാക്കുക. + + താങ്കളുടെ മറ്റ് ഉപകരണങ്ങളിൽ ഫയർഫോക്സിൽ ടാബുകളൊന്നും തുറന്നതായിട്ടില്ല. + + നിങ്ങളുടെ മറ്റ് ഉപകരണങ്ങളിൽ നിന്നുള്ള ടാബുകളുടെ ഒരു ലിസ്റ്റ് കാണുക. + + സമന്വയിപ്പിക്കാനായി പ്രവേശിക്കുക + + + + മികച്ച സൈറ്റുകളുടെ പരിധി കഴിഞ്ഞു + + ഒരു പുതിയ മികച്ച സൈറ്റ് ചേർക്കാൻ, ഒരെണ്ണം നീക്കംചെയ്യുക. സൈറ്റ് ദീർഘനേരം അമർത്തി നീക്കംചെയ്യുക എന്നത് തിരഞ്ഞെടുക്കുക. + + ശരി, മനസ്സിലായി + + diff --git a/app/src/main/res/values-nn-rNO/strings.xml b/app/src/main/res/values-nn-rNO/strings.xml index 8a223584f..e70e2e0b0 100644 --- a/app/src/main/res/values-nn-rNO/strings.xml +++ b/app/src/main/res/values-nn-rNO/strings.xml @@ -894,8 +894,6 @@ Sletter nettlesardata automatisk når du vel «Avslutt» frå hovudmenyen Slettar nettlesardata automatisk når du vel «Avslutt» frå hovudmenyen - - Nettlesarhistorikk Avslutt @@ -980,17 +978,17 @@ Automatisk personvern - Innstillingar for personvern og sikkerheit blokkerer sporfølgjarar, skadeleg kode og selskap som følgjer deg. + Innstillingar for personvern og sikkerheit blokkerer sporarar, skadeleg kode og selskap som følgjer deg. Standard (standard) - Blokkerer færre sporfølgjarar. Sider vert lasta normalt. + Blokkerer færre sporarar. Sider vert lasta normalt. Streng (tilrådd) Streng - Blokkerer fleire sporfølgjarar, reklamer og sprettoppvindauge. Sider vert lasta raskere, men nokre funksjonar fungerer kanskje ikkje. + Blokkerer fleire sporarar, reklamer og sprettoppvindauge. Sider vert lasta raskere, men nokre funksjonar fungerer kanskje ikkje. @@ -1079,19 +1077,19 @@ Standard (standard) - Blokkerer færre sporfølgjarar. Sider vert lasta normalt. + Blokkerer færre sporarar. Sider vert lasta normalt. Kva er blokkert av standard sporingsvern Streng - Blokkerer fleire sporfølgjarar, reklamer og sprettoppvindauge. Sider vert lasta raskere, men nokre funksjonar fungerer kanskje ikkje. + Blokkerer fleire sporarar, reklamer og sprettoppvindauge. Sider vert lasta raskere, men nokre funksjonar fungerer kanskje ikkje. Kva er blokkert av strengt sporingsvern? Tilpassa - Vel kva for sporfølgjarar og skript som skal blokkerast. + Vel kva for sporarar og skript som skal blokkerast. Kva er blokkert av tilpassa sporingsvern @@ -1141,7 +1139,7 @@ Stoppar innlasting av eksterne annonsar, videoar og anna innhald, då dei kan innehalde sporingskode. Kan påverke visse nettstadfunksjonar. - Kvar gong skjoldet er lilla, har %s blokkert sporfølgjarar på ein nettstad. Trykk for meir info. + Kvar gong skjoldet er lilla, har %s blokkert sporarar på ein nettstad. Trykk for meir info. Vern er slått PÅ for denne nettstaden diff --git a/app/src/main/res/values-pa-rIN/strings.xml b/app/src/main/res/values-pa-rIN/strings.xml index 4e4a12c1b..2576c9ad2 100644 --- a/app/src/main/res/values-pa-rIN/strings.xml +++ b/app/src/main/res/values-pa-rIN/strings.xml @@ -886,8 +886,6 @@ ਜਦੋਂ ਤੁਸੀਂ ਮੁੱਖ ਮੇਨੂ ਤੋਂ "ਬਾਹਰ" ਨੂੰ ਚੁਣਦੇ ਹੋ ਤਾਂ ਬਰਾਊਜ਼ ਕਰਨ ਵਾਲਾ ਡਾਟਾ ਆਪਣੇ-ਆਪ ਹਟਾਇਆ ਜਾਂਦਾ ਹੈ ਜਦੋਂ ਤੁਸੀਂ ਮੁੱਖ ਮੇਨੂ ਰਾਹੀਂ \"ਬਾਹਰ\" ਨੂੰ ਚੁਣਦੇ ਹੋ ਤਾਂ ਬਰਾਊਜ਼ ਕੀਤੇ ਡਾਟੇ ਨੂੰ ਆਪਣੇ-ਆਪ ਹਟਾਇਆ ਜਾਂਦਾ ਹੈ - - ਬਰਾਊਜ਼ਿੰਗ ਅਤੀਤ ਬਾਹਰ @@ -1396,6 +1394,8 @@ ਹੋਰ ਡਿਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕਰੋ। ਮੁੜ-ਪ੍ਰਮਾਣਿਤ ਕਰੋ। + + ਟੈਬ ਨੂੰ ਸਿੰਕ ਕਰਨਾ ਸਮਰੱਥ ਕਰੋ। ਸਿੰਕ ਕਰਨ ਲਈ ਸਾਈਨ ਇਨ ਕਰੋ diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index ce32f8d82..bf3f0bda9 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -911,7 +911,7 @@ No entanto, pode ser menos estável. Instale nosso navegador beta se quiser uma experiência de uso mais estável. - Instale o Firefox para Android Beta + Instale o Firefox Beta para Android O Firefox Nightly mudou diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 19c1fd955..53bfa5093 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -917,8 +917,6 @@ Автоматически удаляет данные веб-сёрфинга, когда вы выбираете «Выйти» в главном меню Автоматически удаляет данные веб-сёрфинга, когда вы выбираете \"Выйти\" в главном меню - - История веб-сёрфинга Выйти @@ -940,9 +938,8 @@ Firefox Preview теперь стал Firefox Nightly - ¶ - · Firefox Nightly обновляется каждую ночь и включает в себя новые, экспериментальные возможности.¶ - · Однако, он может быть менее стабилен. Если вы хотите более стабильной работы, загрузите нашу бета-версию браузера. + Firefox Nightly обновляется каждую ночь и включает в себя новые, экспериментальные возможности. + Однако, он может быть менее стабилен. Если вы хотите более стабильной работы, загрузите нашу бета-версию браузера. Загрузить Firefox для Android Бета @@ -950,18 +947,16 @@ Firefox Nightly переехал - ¶ - · Это приложение больше не будет получать обновлений безопасности. Прекратите использование этого приложения и переключитесь на новый Nightly.¶ - · \n\nЧтобы переместить ваши закладки, логины и историю в другое приложение, создайте аккаунт Firefox. + Это приложение больше не будет получать обновлений безопасности. Прекратите использование этого приложения и переключитесь на новый Nightly. + \n\nЧтобы переместить ваши закладки, логины и историю в другое приложение, создайте аккаунт Firefox. Переключиться на новый Nightly Firefox Nightly переехал - ¶ - · Это приложение больше не будет получать обновлений безопасности. Получите новый Nightly и прекратите использование этого приложения.¶ - · \n\nЧтобы переместить ваши закладки, логины и историю в другое приложение, создайте аккаунт Firefox. + Это приложение больше не будет получать обновлений безопасности. Получите новый Nightly и прекратите использование этого приложения. + \n\nЧтобы переместить ваши закладки, логины и историю в другое приложение, создайте аккаунт Firefox. Получить новый Nightly diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index c1f695397..54ae7dbec 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -150,6 +150,8 @@ கருப்பொருள் பயர்பாக்சு கணக்கு + + ஒத்திசைவை மீள்தொடங்க மீண்டும் இணைக்கவும் மொழி @@ -210,4 +212,129 @@ பெறப்பட்ட கீற்றுகள் + + பிற பயர்பாக்சு சாதனங்களிலிருந்து பெறப்பட்ட கீற்றுகளுக்கான அறிவிப்புகள். + + கீற்று பெறப்பட்டது + + கீற்றுகள் பெறப்பட்டன + + + + தடமறியல் பாதுகாப்பு + + தடமறியல் பாதுகாப்பு + + விதிவிலக்குகள் + + எல்லா தளங்களுக்கும் இயக்கு + + மேலும் அறிய + + + சோதனைகள் + + செயலிழப்பு அறிக்கையாளர் + + மொசில்லா புவியிடச்சேவை + + + + ஒத்திசைவை இயக்கு + + புகுபதிகை + + மறுஇணைக்க புகுபதியுங்கள் + + கணக்கை அகற்று + + + படக்கருவியைத் திற + + இரத்து + + + + மேல் + + கீழ் + + + + வெளிர் + + கருமை + + மின்கலச்சேமிப்பான் அமைத்தது + + சாதனக் கருப்பொருளைப் பின்பற்று + + + + அமர்வுகள் + + திரைப்பிடிப்புகள் + + பதிவிறக்கங்கள் + + புத்தகக்குறிகள் + + மேசைக்கணினி புத்தகக்குறிகள் + + புத்தகக்குறிகள் பட்டி + + புத்தகக்குறிகள் கருவிப்பட்டை + + பிற புத்தகக்குறிகள் + + வரலாறு + + வாசிப்புப் பட்டியல் + + தேடல் + + அமைவுகள் + + வரலாறு உருப்படி பட்டி + + மூடு + + + + திறந்த கீற்றுகள் + + கமுக்க அமர்வு + + கமுக்கக் கீற்றுகள் + + கீற்றைச் சேர் + + கீற்றை மூடு + + %s கீற்றை மூடு + + கீற்றுப் பட்டியைத் திற + + எல்லாக் கீற்றுகளையும் மூடு + + கீற்றுகளைப் பகிர் + + கீற்றுப் பட்டி + + தரவைப் பகிர் + + நீக்கு + + சேமி + + பகிர் + + திரட்டில் சேமி + + திரட்டை நீக்கு + + திரட்டை மறுபெயரிடு + + கீற்றுகளைத் திற + diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index d1f2b34c1..f4c1fb584 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -897,8 +897,6 @@ Автоматично видаляє дані перегляду при виборі "Вихід" в головному меню Автоматично видаляє дані перегляду при виборі \"Вихід\" в головному меню - - Історія перегляду Вихід @@ -1444,7 +1442,7 @@ Під’єднати інший пристрій. - Необхідно повторно авторизуватись. + Повторіть автентифікацію. Увімкніть синхронізацію вкладок. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 0a6bbfa8b..32dbd93ab 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -926,8 +926,6 @@ 从主菜单中选择“退出”时,自动删除浏览数据 从主菜单中选择“退出”时,自动删除浏览数据 - - 浏览历史 退出 @@ -947,7 +945,7 @@ - Firefox Preview 即为现在的 Firefox Nightly + Firefox Preview 已迁移至 Firefox Nightly Firefox Nightly 每日获得更新,包含实验性的新功能。 但可能不够稳定,您可以下载我们的 Beta 版浏览器以获得更稳定的体验。 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 4d40f2888..6f7d7c1e6 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -919,8 +919,6 @@ 當您點擊主選單當中的「離開」時,自動刪除瀏覽資料 點擊主選單中的「離開」時,自動清除上網資料 - - 瀏覽紀錄 離開 @@ -940,9 +938,9 @@ - Firefox Nightly 已被 Firefox Preview 取代 + Firefox Nightly 已接手原 Firefox Preview 功能 - Firefox Nightly 每天都會更新一次,當中包含實驗中的新功能,然而這些新功能可能會較不穩定。若須有較穩定的使用體驗,請下載我們的 Beta 測試版。 + Firefox Nightly 每天都會更新,當中包含實驗中的新功能,然而這些新功能可能會較不穩定。\n\n若想要有較穩定的使用體驗,請下載我們的 Beta 測試版。 下載 Firefox for Android Beta 測試版 @@ -950,14 +948,14 @@ Firefox Nightly 版本更新 - 此應用程式不會再收到安全性更新。請改用新版的 Nightly 並停用此應用程式。\n\n請註冊 Firefox 帳號,即可快速移轉書籤、登入資訊、瀏覽紀錄到新版本當中。 + 此應用程式不會再收到安全性更新。請改用新版的 Nightly 並停止使用此版應用程式。\n\n註冊 Firefox 帳號,即可快速移轉書籤、登入資訊、瀏覽紀錄到新版本。 改用新版 Nightly Firefox Nightly 版本更新 - 此應用程式不會再收到安全性更新。請下載新版的 Nightly 並停用此應用程式。\n\n請註冊 Firefox 帳號,即可快速移轉書籤、登入資訊、瀏覽紀錄到新版本當中。 + 此應用程式不會再收到安全性更新。請改用新版的 Nightly 並停止使用此版應用程式。\n\n註冊 Firefox 帳號,即可快速移轉書籤、登入資訊、瀏覽紀錄到新版本。 下載新版 Nightly diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index a8e62f014..159315993 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -109,12 +109,10 @@ 4dp - 8dp - -12dp 16dp - 8dp - 16dp - 40dp + 32dp + 16dp + 72dp 16sp 12sp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5ea444599..738b529bc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -714,6 +714,8 @@ %d tab selected Tabs saved! + + Collection saved! Tab saved! @@ -817,6 +819,10 @@ DENY Are you sure you want to delete %1$s? + + Deleting this tab will delete the entire collection. You can create new collections at any time. + + Delete collection %1$s? Delete diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index e84b80112..e0ffdcf79 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -244,7 +244,8 @@ center @drawable/rounded_button_background match_parent - 48dp + 48dp + wrap_content bold false @color/grey_button_color diff --git a/app/src/main/res/xml/data_choices_preferences.xml b/app/src/main/res/xml/data_choices_preferences.xml index 72c1d7fcc..7dc5c1cc8 100644 --- a/app/src/main/res/xml/data_choices_preferences.xml +++ b/app/src/main/res/xml/data_choices_preferences.xml @@ -2,21 +2,17 @@ - - + - + - + + android:title="@string/preference_experiments" /> diff --git a/app/src/test/java/org/mozilla/fenix/MockNavHostActivity.kt b/app/src/test/java/org/mozilla/fenix/MockNavHostActivity.kt new file mode 100644 index 000000000..b6d40b6ac --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/MockNavHostActivity.kt @@ -0,0 +1,48 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix + +import androidx.appcompat.app.ActionBar +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import io.mockk.mockk +import org.robolectric.Robolectric + +class MockNavHostActivity : AppCompatActivity(), NavHostActivity { + + private val mockActionBar = mockk(relaxed = true) + + override fun getSupportActionBarAndInflateIfNecessary() = mockActionBar +} + +/** + * Set up an added [Fragment] to a [FragmentActivity] that has been initialized to a resumed state. + * + * Variant of [mozilla.components.support.test.robolectric.createAddedTestFragment] that uses + * a custom Fenix activity to hold the fragment. + * + * @param fragmentTag the name that will be used to tag the fragment inside the [FragmentManager]. + * @param fragmentFactory a lambda function that returns a Fragment that will be added to the Activity. + * + * @return The same [Fragment] that was returned from [fragmentFactory] after it got added to the + * Activity. + */ +inline fun createAddedTestFragmentInNavHostActivity( + fragmentTag: String = "test", + fragmentFactory: () -> T +): T { + val activity = Robolectric.buildActivity(MockNavHostActivity::class.java) + .create() + .start() + .resume() + .get() + + return fragmentFactory().also { + activity.supportFragmentManager.beginTransaction() + .add(it, fragmentTag) + .commitNow() + } +} diff --git a/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragmentTest.kt b/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragmentTest.kt new file mode 100644 index 000000000..3c767fe89 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragmentTest.kt @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.addons + +import android.content.Intent.ACTION_VIEW +import androidx.core.net.toUri +import kotlinx.android.synthetic.main.fragment_add_on_permissions.* +import mozilla.components.feature.addons.Addon +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.mozilla.fenix.createAddedTestFragmentInNavHostActivity +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +import org.robolectric.Shadows.shadowOf + +@RunWith(FenixRobolectricTestRunner::class) +class AddonPermissionsDetailsFragmentTest { + + private val addon = Addon( + id = "", + translatableName = mapOf( + Addon.DEFAULT_LOCALE to "Some blank addon" + ) + ) + + @Test + fun `trigger view intent when learn more is clicked`() { + val fragment = createAddedTestFragmentInNavHostActivity { + AddonPermissionsDetailsFragment().apply { + arguments = AddonPermissionsDetailsFragmentArgs(addon).toBundle() + } + } + + assertEquals("Some blank addon", fragment.activity?.title) + + fragment.learn_more_label.performClick() + + val intent = shadowOf(fragment.activity).peekNextStartedActivity() + assertEquals(ACTION_VIEW, intent.action) + assertEquals( + "https://support.mozilla.org/kb/permission-request-messages-firefox-extensions".toUri(), + intent.data + ) + } +} diff --git a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt index f54002236..c70bc2c91 100644 --- a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt @@ -49,7 +49,7 @@ class DefaultSessionControlControllerTest { private val openPrivacyNotice: () -> Unit = mockk(relaxed = true) private val registerCollectionStorageObserver: () -> Unit = mockk(relaxed = true) private val showTabTray: () -> Unit = mockk(relaxed = true) - private val showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit = + private val showDeleteCollectionPrompt: (tabCollection: TabCollection, title: String?, message: String) -> Unit = mockk(relaxed = true) private val metrics: MetricController = mockk(relaxed = true) private val state: HomeFragmentState = mockk(relaxed = true) @@ -137,7 +137,7 @@ class DefaultSessionControlControllerTest { fun handleDeleteCollectionTapped() { val collection: TabCollection = mockk(relaxed = true) controller.handleDeleteCollectionTapped(collection) - verify { showDeleteCollectionPrompt(collection) } + verify { showDeleteCollectionPrompt(collection, null, any()) } } @Test diff --git a/app/src/test/java/org/mozilla/fenix/search/SearchFragmentStoreTest.kt b/app/src/test/java/org/mozilla/fenix/search/SearchFragmentStoreTest.kt index 383b54b66..66bc1f589 100644 --- a/app/src/test/java/org/mozilla/fenix/search/SearchFragmentStoreTest.kt +++ b/app/src/test/java/org/mozilla/fenix/search/SearchFragmentStoreTest.kt @@ -47,6 +47,16 @@ class SearchFragmentStoreTest { assertEquals(true, store.state.showSearchShortcuts) } + @Test + fun hideSearchShortcutEnginePicker() = runBlocking { + val initialState = emptyDefaultState() + val store = SearchFragmentStore(initialState) + + store.dispatch(SearchFragmentAction.UpdateShortcutsAvailability(false)).join() + assertNotSame(initialState, store.state) + assertEquals(false, store.state.showSearchShortcuts) + } + private fun emptyDefaultState(): SearchFragmentState = SearchFragmentState( tabId = null, url = "", @@ -57,6 +67,7 @@ class SearchFragmentStoreTest { showSearchSuggestionsHint = false, showSearchSuggestions = false, showSearchShortcuts = false, + areShortcutsAvailable = true, showClipboardSuggestions = false, showHistorySuggestions = false, showBookmarkSuggestions = false, diff --git a/app/src/test/java/org/mozilla/fenix/ext/AdsTest.kt b/app/src/test/java/org/mozilla/fenix/search/SearchProviderModelTest.kt similarity index 95% rename from app/src/test/java/org/mozilla/fenix/ext/AdsTest.kt rename to app/src/test/java/org/mozilla/fenix/search/SearchProviderModelTest.kt index 76d89dacc..31879d39c 100644 --- a/app/src/test/java/org/mozilla/fenix/ext/AdsTest.kt +++ b/app/src/test/java/org/mozilla/fenix/search/SearchProviderModelTest.kt @@ -2,14 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -package org.mozilla.fenix.ext +package org.mozilla.fenix.search import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import org.mozilla.fenix.search.telemetry.SearchProviderModel -class AdsTest { +class SearchProviderModelTest { private val testSearchProvider = SearchProviderModel( diff --git a/buildSrc/src/main/java/AndroidComponents.kt b/buildSrc/src/main/java/AndroidComponents.kt index 402ba5e65..022c18bd8 100644 --- a/buildSrc/src/main/java/AndroidComponents.kt +++ b/buildSrc/src/main/java/AndroidComponents.kt @@ -3,5 +3,5 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ object AndroidComponents { - const val VERSION = "49.0.20200702190156" + const val VERSION = "49.0.20200706130124" } diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 7b3905e1e..731b33ee1 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -7,14 +7,14 @@ object Versions { const val coroutines = "1.3.3" const val android_gradle_plugin = "3.5.0" const val sentry = "1.7.10" - const val leakcanary = "2.3" + const val leakcanary = "2.4" const val leanplum = "5.4.0" const val osslicenses_plugin = "0.9.5" const val osslicenses_library = "17.0.0" const val detekt = "1.6.0" const val androidx_appcompat = "1.2.0-rc01" - const val androidx_biometric = "1.0.1" + const val androidx_biometric = "1.1.0-alpha01" const val androidx_coordinator_layout = "1.1.0-rc01" const val androidx_constraint_layout = "2.0.0-beta6" const val androidx_preference = "1.1.0" @@ -22,7 +22,7 @@ object Versions { const val androidx_annotation = "1.1.0" const val androidx_lifecycle = "2.2.0" const val androidx_fragment = "1.2.5" - const val androidx_navigation = "2.2.1" + const val androidx_navigation = "2.3.0" const val androidx_recyclerview = "1.1.0" const val androidx_core = "1.2.0" const val androidx_paging = "2.1.0" @@ -44,7 +44,7 @@ object Versions { const val google_ads_id_version = "16.0.0" - const val airbnb_lottie = "3.3.0" + const val airbnb_lottie = "3.4.0" } @Suppress("unused")