Create github actions for Continuous Integration! (#116)

* Add github actions workflows

* Add github actions for CI

* Fix lint and detekt errors

* Add caching to the github actions

* Add the workflow statuses to the README

* Give the jobs more descriptive names

* Consolidate github actions workflows to a single workflow

* Give the steps meaningful names, save detekt and lint results
pull/122/head
Abhijit Kiran Valluri 4 years ago committed by GitHub
parent 77a0a11153
commit df9d8bceae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,101 @@
name: Android build
on:
push:
branches:
- fork
pull_request:
branches:
- fork
schedule:
- cron: '0 12 * * *' # Every day at 12 PM UTC
jobs:
run-build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v1
with:
java-version: 11
- name: Build forkRelease variant of app
uses: eskatos/gradle-command-action@v1
with:
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: assembleForkRelease -PversionName="$(git describe --tags HEAD)"
run-testDebug:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v1
with:
java-version: 11
- name: Run tests
uses: eskatos/gradle-command-action@v1
with:
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: testDebug
run-detekt:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v1
with:
java-version: 11
- name: Run detekt
uses: eskatos/gradle-command-action@v1
with:
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: detekt
- name: Archive detekt results
uses: actions/upload-artifact@v2
with:
name: detekt report
path: build/reports/detekt.html
run-ktlint:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v1
with:
java-version: 11
- name: Run ktlint
uses: eskatos/gradle-command-action@v1
with:
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: ktlint
run-lintDebug:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v1
with:
java-version: 11
- name: Run lintDebug
uses: eskatos/gradle-command-action@v1
with:
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: lintDebug
- name: Archive lint results
uses: actions/upload-artifact@v2
with:
name: lintDebug report
path: app/build/reports/lint-results-debug.html

@ -1,4 +1,5 @@
# Iceweasel Mobile! [![Build Status](https://travis-ci.org/fork-maintainers/iceweasel.svg?branch=fork)](https://travis-ci.org/fork-maintainers/iceweasel) # Iceweasel Mobile! [![Build Status](https://travis-ci.org/fork-maintainers/iceweasel.svg?branch=fork)](https://travis-ci.org/fork-maintainers/iceweasel) ![Android build](https://github.com/fork-maintainers/iceweasel/workflows/Android%20build/badge.svg)
Definitely not brought to you by Mozilla! Definitely not brought to you by Mozilla!
Iceweasel Mobile is a web browser for Android, based on [Mozilla's Fenix version of Firefox](https://github.com/mozilla-mobile/fenix/), [GeckoView](https://mozilla.github.io/geckoview/) and [Mozilla Android Components](https://mozac.org/). Iceweasel Mobile is a web browser for Android, based on [Mozilla's Fenix version of Firefox](https://github.com/mozilla-mobile/fenix/), [GeckoView](https://mozilla.github.io/geckoview/) and [Mozilla Android Components](https://mozac.org/).

@ -20,6 +20,25 @@ import java.util.Map;
public class RemoteMessage implements Parcelable { public class RemoteMessage implements Parcelable {
protected RemoteMessage(Parcel in)
{
}
public static final Creator<RemoteMessage> CREATOR = new Creator<RemoteMessage>()
{
@Override
public RemoteMessage createFromParcel(Parcel in)
{
return new RemoteMessage(in);
}
@Override
public RemoteMessage[] newArray(int size)
{
return new RemoteMessage[size];
}
};
public int describeContents() { public int describeContents() {
return 0; return 0;
} }

@ -9,21 +9,26 @@ import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage import com.google.firebase.messaging.RemoteMessage
import mozilla.components.concept.push.PushService import mozilla.components.concept.push.PushService
abstract class AbstractFirebasePushService() : FirebaseMessagingService(), PushService { abstract class AbstractFirebasePushService : FirebaseMessagingService(), PushService {
override fun start(context: Context) { override fun start(context: Context) {
// no-op
} }
override fun onNewToken(newToken: String) { override fun onNewToken(newToken: String) {
// no-op
} }
override fun onMessageReceived(remoteMessage: RemoteMessage?) { override fun onMessageReceived(remoteMessage: RemoteMessage?) {
// no-op
} }
final override fun stop() { final override fun stop() {
// no-op
} }
override fun deleteToken() { override fun deleteToken() {
// no-op
} }
override fun isServiceAvailable(context: Context): Boolean { override fun isServiceAvailable(context: Context): Boolean {

@ -16,7 +16,6 @@ import mozilla.components.concept.fetch.Request
import mozilla.components.concept.fetch.isSuccess import mozilla.components.concept.fetch.isSuccess
import mozilla.components.feature.addons.Addon import mozilla.components.feature.addons.Addon
import mozilla.components.feature.addons.AddonsProvider import mozilla.components.feature.addons.AddonsProvider
import mozilla.components.feature.addons.amo.AddonCollectionProvider
import mozilla.components.support.base.log.logger.Logger import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.ktx.kotlin.sanitizeURL import mozilla.components.support.ktx.kotlin.sanitizeURL
import mozilla.components.support.ktx.util.readAndDeserialize import mozilla.components.support.ktx.util.readAndDeserialize
@ -359,4 +358,3 @@ internal fun JSONArray.concat(other: JSONArray) {
put(length(), other.getJSONObject(index)) put(length(), other.getJSONObject(index))
} }
} }

@ -34,12 +34,10 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.feature.addons.Addon import mozilla.components.feature.addons.Addon
import mozilla.components.feature.addons.R import mozilla.components.feature.addons.R
import mozilla.components.feature.addons.amo.AddonCollectionProvider
import mozilla.components.feature.addons.ui.translatedName import mozilla.components.feature.addons.ui.translatedName
import mozilla.components.support.base.log.logger.Logger import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.ktx.android.content.appName import mozilla.components.support.ktx.android.content.appName
import mozilla.components.support.ktx.android.content.res.resolveAttribute import mozilla.components.support.ktx.android.content.res.resolveAttribute
import network.novak.fenix.components.PagedAddonCollectionProvider
import java.io.IOException import java.io.IOException
@VisibleForTesting internal const val KEY_INSTALLED_ADDON = "KEY_ADDON" @VisibleForTesting internal const val KEY_INSTALLED_ADDON = "KEY_ADDON"
@ -65,7 +63,7 @@ class PagedAddonInstallationDialogFragment : AppCompatDialogFragment() {
var onConfirmButtonClicked: ((Addon, Boolean) -> Unit)? = null var onConfirmButtonClicked: ((Addon, Boolean) -> Unit)? = null
/** /**
* Reference to the application's [AddonCollectionProvider] to fetch add-on icons. * Reference to the application's [PagedAddonCollectionProvider] to fetch add-on icons.
*/ */
var addonCollectionProvider: PagedAddonCollectionProvider? = null var addonCollectionProvider: PagedAddonCollectionProvider? = null

@ -29,7 +29,6 @@ import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.feature.addons.Addon import mozilla.components.feature.addons.Addon
import mozilla.components.feature.addons.AddonsProvider
import mozilla.components.feature.addons.R import mozilla.components.feature.addons.R
import mozilla.components.feature.addons.ui.AddonsManagerAdapterDelegate import mozilla.components.feature.addons.ui.AddonsManagerAdapterDelegate
import mozilla.components.feature.addons.ui.CustomViewHolder import mozilla.components.feature.addons.ui.CustomViewHolder
@ -40,7 +39,6 @@ import mozilla.components.feature.addons.ui.translatedName
import mozilla.components.feature.addons.ui.translatedSummary import mozilla.components.feature.addons.ui.translatedSummary
import mozilla.components.support.base.log.logger.Logger import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.ktx.android.content.res.resolveAttribute import mozilla.components.support.ktx.android.content.res.resolveAttribute
import network.novak.fenix.components.PagedAddonCollectionProvider
import java.io.IOException import java.io.IOException
import java.text.NumberFormat import java.text.NumberFormat
import java.util.Locale import java.util.Locale
@ -429,4 +427,3 @@ private fun Addon.inDisabledSection() = isInstalled() && isSupported() && !isEna
internal fun getFormattedAmount(amount: Int): String { internal fun getFormattedAmount(amount: Int): String {
return NumberFormat.getNumberInstance(Locale.getDefault()).format(amount) return NumberFormat.getNumberInstance(Locale.getDefault()).format(amount)
} }

@ -56,12 +56,12 @@ enum class ReleaseChannel {
*/ */
val isFenix: Boolean val isFenix: Boolean
get() = !isFennec get() = !isFennec
/** /**
* Is this a rebranded fork? * Is this a rebranded fork?
*/ */
val isFork: Boolean val isFork: Boolean
get() = when (this) { get() = when (this) {
ForkDebug -> true ForkDebug -> true
ForkRelease -> true ForkRelease -> true
else -> false else -> false

@ -34,11 +34,10 @@ object FeatureFlags {
/** /**
* Enables wait til first contentful paint * Enables wait til first contentful paint
*/ */
val waitUntilPaintToDraw = true const val waitUntilPaintToDraw = true
/** /**
* Enables downloads with external download managers. * Enables downloads with external download managers.
*/ */
val externalDownloadManager = true const val externalDownloadManager = true
} }

@ -6,7 +6,12 @@ package org.mozilla.fenix.addons
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.Gravity
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityEvent
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
@ -16,9 +21,12 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.fragment_add_ons_management.* import kotlinx.android.synthetic.main.fragment_add_ons_management.addonProgressOverlay
import kotlinx.android.synthetic.main.fragment_add_ons_management.view.* import kotlinx.android.synthetic.main.fragment_add_ons_management.view.add_ons_empty_message
import kotlinx.android.synthetic.main.overlay_add_on_progress.view.* import kotlinx.android.synthetic.main.fragment_add_ons_management.view.add_ons_list
import kotlinx.android.synthetic.main.fragment_add_ons_management.view.add_ons_progress_bar
import kotlinx.android.synthetic.main.overlay_add_on_progress.view.add_ons_overlay_text
import kotlinx.android.synthetic.main.overlay_add_on_progress.view.cancel_button
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -26,8 +34,8 @@ import mozilla.components.feature.addons.Addon
import mozilla.components.feature.addons.AddonManagerException import mozilla.components.feature.addons.AddonManagerException
import mozilla.components.feature.addons.ui.PermissionsDialogFragment import mozilla.components.feature.addons.ui.PermissionsDialogFragment
import mozilla.components.feature.addons.ui.translatedName import mozilla.components.feature.addons.ui.translatedName
import network.novak.fenix.components.PagedAddonsManagerAdapter
import network.novak.fenix.components.PagedAddonInstallationDialogFragment import network.novak.fenix.components.PagedAddonInstallationDialogFragment
import network.novak.fenix.components.PagedAddonsManagerAdapter
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
@ -42,7 +50,7 @@ import java.util.concurrent.CancellationException
/** /**
* Fragment use for managing add-ons. * Fragment use for managing add-ons.
*/ */
@Suppress("TooManyFunctions") @Suppress("LargeClass", "TooManyFunctions")
class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) { class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) {
/** /**

@ -82,7 +82,6 @@ class Components(private val context: Context) {
) )
} }
val appStartupTelemetry by lazy { AppStartupTelemetry(analytics.metrics) } val appStartupTelemetry by lazy { AppStartupTelemetry(analytics.metrics) }
@Suppress("MagicNumber") @Suppress("MagicNumber")

@ -7,8 +7,6 @@ package org.mozilla.fenix.components
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.withContext
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
/** /**

@ -1,3 +1,25 @@
/* 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/. */
/* Added the Mozilla Public License above to avoid failing detekt rule */
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mozilla.fenix.components.topsheet package org.mozilla.fenix.components.topsheet
import android.animation.ValueAnimator import android.animation.ValueAnimator
@ -6,7 +28,12 @@ import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import android.util.AttributeSet import android.util.AttributeSet
import android.util.TypedValue import android.util.TypedValue
import android.view.* import android.view.AbsSavedState
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.ViewConfiguration
import android.view.ViewGroup
import androidx.annotation.IntDef import androidx.annotation.IntDef
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.NestedScrollingChild import androidx.core.view.NestedScrollingChild
@ -19,47 +46,31 @@ import com.google.android.material.shape.ShapeAppearanceModel
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import kotlin.math.abs import kotlin.math.abs
/* /**
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ /**
* An interaction behavior plugin for a child view of [CoordinatorLayout] to make it work as * An interaction behavior plugin for a child view of [CoordinatorLayout] to make it work as
* a top sheet. * a top sheet.
*/ */
@Suppress("TooManyFunctions", "LargeClass")
class TopSheetBehavior<V : View?> class TopSheetBehavior<V : View?>
/** /**
* Default constructor for inflating TopSheetBehaviors from layout. * Default constructor for inflating TopSheetBehaviors from layout.
* *
* @param context The [Context]. * @param context The [Context].
* @param attrs The [AttributeSet]. * @param attrs The [AttributeSet].
*/(context: Context, attrs: AttributeSet?) : CoordinatorLayout.Behavior<V>(context, attrs) { */(context: Context, attrs: AttributeSet?) : CoordinatorLayout.Behavior<V>(context, attrs) {
/** /**
* Callback for monitoring events about top sheets. * Callback for monitoring events about top sheets.
*/ */
abstract class TopSheetCallback { interface TopSheetCallback {
/** /**
* Called when the top sheet changes its state. * Called when the top sheet changes its state.
* *
* @param topSheet The top sheet view. * @param topSheet The top sheet view.
* @param newState The new state. This will be one of [.STATE_DRAGGING], * @param newState The new state. This will be one of [.STATE_DRAGGING],
* [.STATE_SETTLING], [.STATE_EXPANDED], * [.STATE_SETTLING], [.STATE_EXPANDED],
* [.STATE_COLLAPSED], or [.STATE_HIDDEN]. * [.STATE_COLLAPSED], or [.STATE_HIDDEN].
*/ */
abstract fun onStateChanged( fun onStateChanged(topSheet: View, @State newState: Int)
topSheet: View,
@State newState: Int
)
/** /**
* Called when the top sheet is being dragged. * Called when the top sheet is being dragged.
@ -67,13 +78,9 @@ class TopSheetBehavior<V : View?>
* @param topSheet The top sheet view. * @param topSheet The top sheet view.
* @param slideOffset The new offset of this top sheet within its range, from 0 to 1 * @param slideOffset The new offset of this top sheet within its range, from 0 to 1
* when it is moving upward, and from 0 to -1 when it moving downward. * when it is moving upward, and from 0 to -1 when it moving downward.
* @param isOpening detect showing * @param isOpening detect showing
*/ */
abstract fun onSlide( fun onSlide(topSheet: View, slideOffset: Float, isOpening: Boolean?)
topSheet: View,
slideOffset: Float,
isOpening: Boolean?
)
} }
/** /**
@ -148,7 +155,7 @@ class TopSheetBehavior<V : View?>
a.hasValue(R.styleable.BottomSheetBehavior_Layout_shapeAppearance) a.hasValue(R.styleable.BottomSheetBehavior_Layout_shapeAppearance)
createMaterialShapeDrawable(context, attrs!!) createMaterialShapeDrawable(context, attrs!!)
createShapeValueAnimator() createShapeValueAnimator()
peekHeight = context.resources.displayMetrics.heightPixels * 3 / 4 peekHeight = context.resources.displayMetrics.heightPixels * PEEK_HEIGHT_RATIO
isHideable = a.getBoolean( isHideable = a.getBoolean(
R.styleable.BottomSheetBehavior_Layout_behavior_hideable, R.styleable.BottomSheetBehavior_Layout_behavior_hideable,
false false
@ -188,6 +195,7 @@ class TopSheetBehavior<V : View?>
} }
} }
@Suppress("ComplexMethod")
override fun onLayoutChild( override fun onLayoutChild(
parent: CoordinatorLayout, parent: CoordinatorLayout,
child: V, child: V,
@ -238,6 +246,7 @@ class TopSheetBehavior<V : View?>
return true return true
} }
@Suppress("ComplexMethod", "ReturnCount")
override fun onInterceptTouchEvent( override fun onInterceptTouchEvent(
parent: CoordinatorLayout, parent: CoordinatorLayout,
child: V, child: V,
@ -306,7 +315,7 @@ class TopSheetBehavior<V : View?>
return true return true
} }
if (mViewDragHelper != null) { if (mViewDragHelper != null) {
//no crash // no crash
mViewDragHelper!!.processTouchEvent(event) mViewDragHelper!!.processTouchEvent(event)
// Record the velocity // Record the velocity
if (action == MotionEvent.ACTION_DOWN) { if (action == MotionEvent.ACTION_DOWN) {
@ -318,13 +327,12 @@ class TopSheetBehavior<V : View?>
mVelocityTracker!!.addMovement(event) mVelocityTracker!!.addMovement(event)
// The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it
// to capture the top sheet in case it is not captured and the touch slop is passed. // to capture the top sheet in case it is not captured and the touch slop is passed.
if (action == MotionEvent.ACTION_MOVE && !mIgnoreEvents) { if (action == MotionEvent.ACTION_MOVE && !mIgnoreEvents &&
if (abs(mInitialY - event.y) > mViewDragHelper!!.touchSlop) { abs(mInitialY - event.y) > mViewDragHelper!!.touchSlop) {
mViewDragHelper!!.captureChildView( mViewDragHelper!!.captureChildView(
child, child,
event.getPointerId(event.actionIndex) event.getPointerId(event.actionIndex)
) )
}
} }
} }
return !mIgnoreEvents return !mIgnoreEvents
@ -343,8 +351,12 @@ class TopSheetBehavior<V : View?>
} }
override fun onNestedPreScroll( override fun onNestedPreScroll(
coordinatorLayout: CoordinatorLayout, child: V, target: View, dx: Int, coordinatorLayout: CoordinatorLayout,
dy: Int, consumed: IntArray child: V,
target: View,
dx: Int,
dy: Int,
consumed: IntArray
) { ) {
val scrollingChild = mNestedScrollingChildRef!!.get() val scrollingChild = mNestedScrollingChildRef!!.get()
if (target !== scrollingChild) { if (target !== scrollingChild) {
@ -430,8 +442,11 @@ class TopSheetBehavior<V : View?>
} }
override fun onNestedPreFling( override fun onNestedPreFling(
coordinatorLayout: CoordinatorLayout, child: V, target: View, coordinatorLayout: CoordinatorLayout,
velocityX: Float, velocityY: Float child: V,
target: View,
velocityX: Float,
velocityY: Float
): Boolean { ): Boolean {
return target === mNestedScrollingChildRef!!.get() && return target === mNestedScrollingChildRef!!.get() &&
(mState != STATE_EXPANDED || (mState != STATE_EXPANDED ||
@ -466,9 +481,9 @@ class TopSheetBehavior<V : View?>
} }
if (mViewRef == null) { if (mViewRef == null) {
// The view is not laid out yet; modify mState and let onLayoutChild handle it later // The view is not laid out yet; modify mState and let onLayoutChild handle it later
if (state == STATE_COLLAPSED || state == STATE_EXPANDED || val stateCondition = state == STATE_COLLAPSED || state == STATE_EXPANDED ||
isHideable && state == STATE_HIDDEN isHideable && state == STATE_HIDDEN
) { if (stateCondition) {
mState = state mState = state
} }
return return
@ -509,6 +524,7 @@ class TopSheetBehavior<V : View?>
} }
} }
@Suppress("NestedBlockDepth")
private fun updateDrawableForTargetState(@BottomSheetBehavior.State state: Int) { private fun updateDrawableForTargetState(@BottomSheetBehavior.State state: Int) {
if (state == BottomSheetBehavior.STATE_SETTLING) { if (state == BottomSheetBehavior.STATE_SETTLING) {
// Special case: we want to know which state we're settling to, so wait for another call. // Special case: we want to know which state we're settling to, so wait for another call.
@ -567,11 +583,12 @@ class TopSheetBehavior<V : View?>
private val yVelocity: Float private val yVelocity: Float
get() { get() {
mVelocityTracker!!.computeCurrentVelocity(1000, mMaximumVelocity) mVelocityTracker!!.computeCurrentVelocity(VELOCITY_UNITS, mMaximumVelocity)
return mVelocityTracker!!.getYVelocity(mActivePointerId) return mVelocityTracker!!.getYVelocity(mActivePointerId)
} }
private val mDragCallback: ViewDragHelper.Callback = object : ViewDragHelper.Callback() { private val mDragCallback: ViewDragHelper.Callback = object : ViewDragHelper.Callback() {
@Suppress("ReturnCount")
override fun tryCaptureView( override fun tryCaptureView(
child: View, child: View,
pointerId: Int pointerId: Int
@ -709,7 +726,6 @@ class TopSheetBehavior<V : View?>
} }
} }
private fun dispatchOnSlide(top: Int) { private fun dispatchOnSlide(top: Int) {
val topSheet: View? = mViewRef!!.get() val topSheet: View? = mViewRef!!.get()
if (topSheet != null && mCallback != null) { if (topSheet != null && mCallback != null) {
@ -742,7 +758,6 @@ class TopSheetBehavior<V : View?>
setStateInternal(mTargetState) setStateInternal(mTargetState)
} }
} }
} }
private class SavedState(superState: Parcelable?, @State val state: Int) : private class SavedState(superState: Parcelable?, @State val state: Int) :
@ -806,5 +821,7 @@ class TopSheetBehavior<V : View?>
private const val CORNER_ANIMATION_DURATION = 500 private const val CORNER_ANIMATION_DURATION = 500
private val DEF_STYLE_RES = R.style.Widget_Design_BottomSheet_Modal private val DEF_STYLE_RES = R.style.Widget_Design_BottomSheet_Modal
private const val PEEK_HEIGHT_RATIO = 3 / 4
private const val VELOCITY_UNITS = 1000
} }
} }

@ -23,7 +23,18 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageVie
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSitePagerViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSitePagerViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.* import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingAutomaticSignInViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingManualSignInViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingPrivacyNoticeViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingPrivateBrowsingViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingSectionHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTabsTrayLayoutViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingThemePickerViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingToolbarPositionPickerViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTrackingProtectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingWhatsNewViewHolder
import org.mozilla.fenix.home.tips.ButtonTipViewHolder import org.mozilla.fenix.home.tips.ButtonTipViewHolder
import mozilla.components.feature.tab.collections.Tab as ComponentTab import mozilla.components.feature.tab.collections.Tab as ComponentTab

@ -8,9 +8,6 @@ import android.view.View
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.onboarding_tabs_tray_layout.view.* import kotlinx.android.synthetic.main.onboarding_tabs_tray_layout.view.*
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.Event.OnboardingTrackingProtection.Setting
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.onboarding.OnboardingRadioButton import org.mozilla.fenix.onboarding.OnboardingRadioButton
import org.mozilla.fenix.utils.view.addToRadioGroup import org.mozilla.fenix.utils.view.addToRadioGroup
@ -44,7 +41,6 @@ class OnboardingTabsTrayLayoutViewHolder(view: View) : RecyclerView.ViewHolder(v
reverseTabOrderInTabsTray = !enabled reverseTabOrderInTabsTray = !enabled
useNewTabFloatingActionButton = !enabled useNewTabFloatingActionButton = !enabled
placeNewTabFloatingActionButtonAtTop = false placeNewTabFloatingActionButtonAtTop = false
} }
} }

@ -10,7 +10,11 @@ import android.os.Build.VERSION.SDK_INT
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit import androidx.core.content.edit
import androidx.preference.* import androidx.preference.EditTextPreference
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
@ -25,7 +29,7 @@ import org.mozilla.fenix.utils.view.addToRadioGroup
* Lets the user customize the UI. * Lets the user customize the UI.
*/ */
@Suppress("TooManyFunctions") @Suppress("LargeClass", "TooManyFunctions")
class CustomizationFragment : PreferenceFragmentCompat() { class CustomizationFragment : PreferenceFragmentCompat() {
private lateinit var radioLightTheme: RadioButtonPreference private lateinit var radioLightTheme: RadioButtonPreference
private lateinit var radioDarkTheme: RadioButtonPreference private lateinit var radioDarkTheme: RadioButtonPreference
@ -154,7 +158,8 @@ class CustomizationFragment : PreferenceFragmentCompat() {
onPreferenceChangeListener = SharedPreferenceUpdater() onPreferenceChangeListener = SharedPreferenceUpdater()
} }
val reverseOrderPref = requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_reverse_tab_order).apply { val reverseOrderPref = requirePreference<SwitchPreference>(
R.string.pref_key_tabs_tray_reverse_tab_order).apply {
if (context.settings().enableCompactTabs) { if (context.settings().enableCompactTabs) {
isChecked = false isChecked = false
isEnabled = false isEnabled = false
@ -210,8 +215,6 @@ class CustomizationFragment : PreferenceFragmentCompat() {
true true
} }
} }
} }
private fun setupHomeCategory() { private fun setupHomeCategory() {
@ -240,7 +243,6 @@ class CustomizationFragment : PreferenceFragmentCompat() {
isChecked = context.settings().isSwipeToolbarToSwitchTabsEnabled isChecked = context.settings().isSwipeToolbarToSwitchTabsEnabled
onPreferenceChangeListener = SharedPreferenceUpdater() onPreferenceChangeListener = SharedPreferenceUpdater()
} }
} }
private fun setupAddonsCustomizationCategory() { private fun setupAddonsCustomizationCategory() {
@ -253,6 +255,5 @@ class CustomizationFragment : PreferenceFragmentCompat() {
text = context.settings().customAddonsCollection text = context.settings().customAddonsCollection
onPreferenceChangeListener = SharedPreferenceUpdater() onPreferenceChangeListener = SharedPreferenceUpdater()
} }
} }
} }

@ -164,6 +164,7 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
} }
} }
@Suppress("LongMethod")
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)

@ -148,7 +148,7 @@ class TabTrayView(
if (!isTabsTrayFullScreenMode) { if (!isTabsTrayFullScreenMode) {
if (useTopTabsTray) { if (useTopTabsTray) {
(behavior as TopSheetBehavior).setTopSheetCallback(object : (behavior as TopSheetBehavior).setTopSheetCallback(object :
TopSheetBehavior.TopSheetCallback() { TopSheetBehavior.TopSheetCallback {
override fun onSlide(topSheet: View, slideOffset: Float, isOpening: Boolean?) { override fun onSlide(topSheet: View, slideOffset: Float, isOpening: Boolean?) {
if (interactor.onModeRequested() is Mode.Normal && useFab) { if (interactor.onModeRequested() is Mode.Normal && useFab) {
if (slideOffset >= SLIDE_OFFSET) { if (slideOffset >= SLIDE_OFFSET) {
@ -262,9 +262,9 @@ class TabTrayView(
concatAdapter.addAdapter(syncedTabsController.adapter) concatAdapter.addAdapter(syncedTabsController.adapter)
} }
if (hasAccessibilityEnabled) { if (hasAccessibilityEnabled) {
tabsAdapter.notifyItemRangeChanged(0, tabs.size) tabsAdapter.notifyItemRangeChanged(0, tabs.size)
} }
if (!hasLoaded) { if (!hasLoaded) {
hasLoaded = true hasLoaded = true
@ -321,7 +321,7 @@ class TabTrayView(
private fun gridViewNumberOfCols(context: Context): Int { private fun gridViewNumberOfCols(context: Context): Int {
val displayMetrics = context.resources.displayMetrics val displayMetrics = context.resources.displayMetrics
val dpWidth = displayMetrics.widthPixels / displayMetrics.density val dpWidth = displayMetrics.widthPixels / displayMetrics.density
val columnWidthDp = 190 val columnWidthDp = COLUMN_WIDTH_DP
val columnCount = (dpWidth / columnWidthDp).toInt() val columnCount = (dpWidth / columnWidthDp).toInt()
return if (columnCount >= 2) columnCount else 2 return if (columnCount >= 2) columnCount else 2
} }
@ -359,41 +359,51 @@ class TabTrayView(
} }
fun updateTabsTrayLayout() { fun updateTabsTrayLayout() {
if (enableCompactTabs) {
setupCompactTabsTrayLayout()
} else {
setupRegularTabsTrayLayout()
}
}
private fun setupCompactTabsTrayLayout() {
view.tabsTray.apply { view.tabsTray.apply {
if (enableCompactTabs) { val gridLayoutManager = GridLayoutManager(container.context, gridViewNumberOfCols(container.context))
val gridLayoutManager = GridLayoutManager(container.context, gridViewNumberOfCols(container.context)) if (useTopTabsTray) {
if (useTopTabsTray) { gridLayoutManager.reverseLayout = true
gridLayoutManager.reverseLayout = true }
} gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int {
override fun getSpanSize(position: Int): Int { val numTabs = tabsAdapter.itemCount
val numTabs = tabsAdapter.itemCount return if (position < numTabs) {
return if (position < numTabs) { 1
1 } else {
} else { gridViewNumberOfCols(container.context)
gridViewNumberOfCols(container.context)
}
} }
} }
}
layoutManager = gridLayoutManager layoutManager = gridLayoutManager
} else { }
val linearLayoutManager = LinearLayoutManager(container.context) }
if (useTopTabsTray) {
if (!reverseTabOrderInTabsTray) { private fun setupRegularTabsTrayLayout() {
linearLayoutManager.reverseLayout = true view.tabsTray.apply {
} else { val linearLayoutManager = LinearLayoutManager(container.context)
linearLayoutManager.stackFromEnd = true if (useTopTabsTray) {
} if (!reverseTabOrderInTabsTray) {
linearLayoutManager.reverseLayout = true
} else { } else {
if (reverseTabOrderInTabsTray) { linearLayoutManager.stackFromEnd = true
linearLayoutManager.reverseLayout = true }
linearLayoutManager.stackFromEnd = true } else {
} if (reverseTabOrderInTabsTray) {
linearLayoutManager.reverseLayout = true
linearLayoutManager.stackFromEnd = true
} }
layoutManager = linearLayoutManager
} }
layoutManager = linearLayoutManager
} }
} }
@ -729,6 +739,7 @@ class TabTrayView(
private const val NORMAL_TOP_MARGIN = 8 private const val NORMAL_TOP_MARGIN = 8
private const val NORMAL_BOTTOM_MARGIN = 8 private const val NORMAL_BOTTOM_MARGIN = 8
private const val NORMAL_HANDLE_PERCENT_WIDTH = 0.1F private const val NORMAL_HANDLE_PERCENT_WIDTH = 0.1F
private const val COLUMN_WIDTH_DP = 190
} }
} }

@ -30,7 +30,14 @@ import mozilla.components.support.images.loader.ImageLoader
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.ext.* import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getMediaStateForSession
import org.mozilla.fenix.ext.increaseTapArea
import org.mozilla.fenix.ext.removeAndDisable
import org.mozilla.fenix.ext.removeTouchDelegate
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.showAndEnable
import org.mozilla.fenix.ext.toShortUrl
import org.mozilla.fenix.utils.Do import org.mozilla.fenix.utils.Do
import kotlin.math.max import kotlin.math.max

@ -15,7 +15,6 @@ import android.view.accessibility.AccessibilityManager
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.annotation.VisibleForTesting.PRIVATE import androidx.annotation.VisibleForTesting.PRIVATE
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.preference.EditTextPreference
import mozilla.components.feature.sitepermissions.SitePermissionsRules import mozilla.components.feature.sitepermissions.SitePermissionsRules
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action
import mozilla.components.feature.sitepermissions.SitePermissionsRules.AutoplayAction import mozilla.components.feature.sitepermissions.SitePermissionsRules.AutoplayAction

Loading…
Cancel
Save