Fixes #127: Add architecture classes
parent
262df015b1
commit
69e9617272
|
@ -65,12 +65,23 @@ android.applicationVariants.all { variant ->
|
||||||
println("Version code: " + variant.mergedFlavor.versionCode)
|
println("Version code: " + variant.mergedFlavor.versionCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
androidExtensions {
|
||||||
|
experimental = true
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation Deps.kotlin_stdlib
|
implementation Deps.kotlin_stdlib
|
||||||
implementation Deps.androidx_appcompat
|
implementation Deps.androidx_appcompat
|
||||||
implementation Deps.androidx_constraintlayout
|
implementation Deps.androidx_constraintlayout
|
||||||
|
|
||||||
|
implementation Deps.rxAndroid
|
||||||
|
implementation Deps.rxKotlin
|
||||||
|
implementation Deps.anko_commons
|
||||||
|
implementation Deps.anko_sdk
|
||||||
|
implementation Deps.anko_appcompat
|
||||||
|
implementation Deps.anko_constraintlayout
|
||||||
|
|
||||||
implementation Deps.mozilla_concept_engine
|
implementation Deps.mozilla_concept_engine
|
||||||
implementation Deps.mozilla_concept_storage
|
implementation Deps.mozilla_concept_storage
|
||||||
implementation Deps.mozilla_concept_toolbar
|
implementation Deps.mozilla_concept_toolbar
|
||||||
|
|
|
@ -9,15 +9,15 @@ import android.transition.TransitionInflater
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
import androidx.navigation.fragment.FragmentNavigator
|
import androidx.navigation.fragment.FragmentNavigator
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import kotlinx.android.synthetic.main.fragment_home.*
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.home.sessions.SessionsAdapter
|
import org.mozilla.fenix.home.sessions.SessionsComponent
|
||||||
|
import org.mozilla.fenix.home.sessions.layoutComponents
|
||||||
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
|
|
||||||
class HomeFragment : Fragment() {
|
class HomeFragment : Fragment() {
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
|
@ -27,8 +27,6 @@ class HomeFragment : Fragment() {
|
||||||
return inflater.inflate(R.layout.fragment_home, container, false)
|
return inflater.inflate(R.layout.fragment_home, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var sessionsAdapter: SessionsAdapter
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
@ -36,8 +34,6 @@ class HomeFragment : Fragment() {
|
||||||
menuButton.visibility = View.GONE
|
menuButton.visibility = View.GONE
|
||||||
privateBrowsingButton.visibility = View.GONE
|
privateBrowsingButton.visibility = View.GONE
|
||||||
|
|
||||||
sessionsAdapter = SessionsAdapter()
|
|
||||||
|
|
||||||
toolbar_wrapper.clipToOutline = false
|
toolbar_wrapper.clipToOutline = false
|
||||||
toolbar.setOnClickListener { it ->
|
toolbar.setOnClickListener { it ->
|
||||||
val extras = FragmentNavigator.Extras.Builder().addSharedElement(
|
val extras = FragmentNavigator.Extras.Builder().addSharedElement(
|
||||||
|
@ -46,11 +42,8 @@ class HomeFragment : Fragment() {
|
||||||
Navigation.findNavController(it).navigate(R.id.action_homeFragment_to_searchFragment, null, null, extras)
|
Navigation.findNavController(it).navigate(R.id.action_homeFragment_to_searchFragment, null, null, extras)
|
||||||
}
|
}
|
||||||
|
|
||||||
session_list.apply {
|
SessionsComponent(homeLayout, ActionBusFactory.get(this)).setup()
|
||||||
adapter = sessionsAdapter
|
layoutComponents(homeLayout)
|
||||||
layoutManager = LinearLayoutManager(requireContext())
|
|
||||||
setHasFixedSize(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* 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.home.sessions
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import mozilla.components.browser.session.Session
|
||||||
|
import org.mozilla.fenix.mvi.*
|
||||||
|
|
||||||
|
class SessionsComponent(private val container: ViewGroup, override val bus: ActionBusFactory) :
|
||||||
|
UIComponent<SessionsState, SessionsAction, SessionsChange>(bus) {
|
||||||
|
|
||||||
|
override var initialState: SessionsState = SessionsState(emptyList())
|
||||||
|
|
||||||
|
override val reducer : (SessionsState, SessionsChange) -> SessionsState = { state, change ->
|
||||||
|
when (change) {
|
||||||
|
is SessionsChange.SessionsChanged -> state // copy state with changes here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() = SessionsUIView(container, bus)
|
||||||
|
|
||||||
|
@SuppressLint("CheckResult")
|
||||||
|
fun setup(): SessionsComponent {
|
||||||
|
render(reducer)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class SessionsState(val sessions: List<Session>) : ViewState
|
||||||
|
|
||||||
|
sealed class SessionsAction : Action {
|
||||||
|
object Select : SessionsAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class SessionsChange : Change {
|
||||||
|
object SessionsChanged : SessionsChange()
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package org.mozilla.fenix.home.sessions
|
||||||
|
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID
|
||||||
|
import kotlinx.android.synthetic.main.component_sessions.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
|
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.BOTTOM
|
||||||
|
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.TOP
|
||||||
|
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.START
|
||||||
|
import org.jetbrains.anko.constraint.layout.ConstraintSetBuilder.Side.END
|
||||||
|
import org.jetbrains.anko.constraint.layout.applyConstraintSet
|
||||||
|
import org.mozilla.fenix.home.HomeFragment
|
||||||
|
|
||||||
|
fun HomeFragment.layoutComponents(layout: ConstraintLayout) {
|
||||||
|
layout.applyConstraintSet {
|
||||||
|
session_list {
|
||||||
|
connect(
|
||||||
|
BOTTOM to BOTTOM of PARENT_ID,
|
||||||
|
START to START of PARENT_ID,
|
||||||
|
END to END of PARENT_ID,
|
||||||
|
TOP to BOTTOM of toolbar_wrapper
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* 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.home.sessions
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.reactivex.functions.Consumer
|
||||||
|
import kotlinx.android.synthetic.main.component_sessions.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
|
import org.mozilla.fenix.mvi.UIView
|
||||||
|
|
||||||
|
class SessionsUIView(container: ViewGroup, bus: ActionBusFactory) : UIView<SessionsState>(container, bus) {
|
||||||
|
|
||||||
|
val view: ConstraintLayout = LayoutInflater.from(container.context)
|
||||||
|
.inflate(R.layout.component_sessions, container, true) as ConstraintLayout
|
||||||
|
|
||||||
|
private var sessionAdapter = SessionsAdapter()
|
||||||
|
|
||||||
|
init {
|
||||||
|
session_list.apply {
|
||||||
|
layoutManager = LinearLayoutManager(view.context)
|
||||||
|
adapter = sessionAdapter
|
||||||
|
setHasFixedSize(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateView() = Consumer<SessionsState> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Netflix, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Created by Juliano Moraes, Rohan Dhruva, Emmanuel Boudrant.
|
||||||
|
*/
|
||||||
|
package org.mozilla.fenix.mvi
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleObserver
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.OnLifecycleEvent
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.rxkotlin.merge
|
||||||
|
import io.reactivex.subjects.PublishSubject
|
||||||
|
import io.reactivex.subjects.Subject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It implements a Factory pattern generating Rx Subjects based on Event Types.
|
||||||
|
* It maintain a map of Rx Subjects, one per type per instance of ActionBusFactory.
|
||||||
|
*
|
||||||
|
* @param owner is a LifecycleOwner used to auto dispose based on destroy observable
|
||||||
|
*/
|
||||||
|
class ActionBusFactory private constructor(val owner: LifecycleOwner) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private val buses = mutableMapOf<LifecycleOwner, ActionBusFactory>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the [ActionBusFactory] associated to the [LifecycleOwner]. It there is no bus it will create one.
|
||||||
|
* If the [LifecycleOwner] used is a fragment it use [Fragment#getViewLifecycleOwner()]
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun get(lifecycleOwner: LifecycleOwner): ActionBusFactory {
|
||||||
|
return with(lifecycleOwner) {
|
||||||
|
var bus = buses[lifecycleOwner]
|
||||||
|
if (bus == null) {
|
||||||
|
bus = ActionBusFactory(lifecycleOwner)
|
||||||
|
buses[lifecycleOwner] = bus
|
||||||
|
// LifecycleOwner
|
||||||
|
lifecycleOwner.lifecycle.addObserver(bus.observer)
|
||||||
|
}
|
||||||
|
bus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
|
val map = HashMap<Class<*>, Subject<*>>()
|
||||||
|
|
||||||
|
internal val observer = object : LifecycleObserver {
|
||||||
|
|
||||||
|
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||||
|
fun onDestroy() {
|
||||||
|
map.forEach { entry -> entry.value.onComplete() }
|
||||||
|
buses.remove(owner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> create(clazz: Class<T>): Subject<T> {
|
||||||
|
val subject = PublishSubject.create<T>().toSerialized()
|
||||||
|
map[clazz] = subject
|
||||||
|
return subject
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* emit will create (if needed) or use the existing Rx Subject to send events.
|
||||||
|
*
|
||||||
|
* @param clazz is the Event Class
|
||||||
|
* @param event is the instance of the Event to be sent
|
||||||
|
*/
|
||||||
|
fun <T : Action> emit(clazz: Class<T>, event: T) {
|
||||||
|
val subject = if (map[clazz] != null) map[clazz] else create(clazz)
|
||||||
|
(subject as Subject<T>).onNext(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**x
|
||||||
|
* getSafeManagedObservable returns an Rx Observable which is
|
||||||
|
* *Safe* against reentrant events as it is serialized and
|
||||||
|
* *Managed* since it disposes itself based on the lifecycle
|
||||||
|
*
|
||||||
|
* @param clazz is the class of the event type used by this observable
|
||||||
|
*/
|
||||||
|
fun <T : Action> getSafeManagedObservable(clazz: Class<T>): Observable<T> {
|
||||||
|
return if (map[clazz] != null) map[clazz] as Observable<T> else create(clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logMergedObservables() {
|
||||||
|
// TODO make this observe new items in the map and combine them
|
||||||
|
map.values.merge().compose(logState()).subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getDestroyObservable observes to Lifecycle owner and fires when
|
||||||
|
* lifecycle.currentState == Lifecycle.State.DESTROYED
|
||||||
|
*/
|
||||||
|
fun getDestroyObservable(): Observable<Unit> {
|
||||||
|
return owner.createDestroyObservable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension on [LifecycleOwner] used to emit an event.
|
||||||
|
*/
|
||||||
|
inline fun <reified T : Action> LifecycleOwner.emit(event: T) =
|
||||||
|
kotlin.with(ActionBusFactory.get(this)) {
|
||||||
|
getSafeManagedObservable(T::class.java)
|
||||||
|
emit(T::class.java, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension on [LifecycleOwner] used used to get the state observable.
|
||||||
|
*/
|
||||||
|
inline fun <reified T : Action> LifecycleOwner.getSafeManagedObservable(): Observable<T> =
|
||||||
|
ActionBusFactory.get(this).getSafeManagedObservable(T::class.java)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns a destroy observable that can be passed to [org.mozilla.fenix.mvi.UIView]s as needed.
|
||||||
|
* This is deliberately scoped to the attached [LifecycleOwner]'s [Lifecycle.Event.ON_DESTROY]
|
||||||
|
* because a viewholder can be reused across adapter destroys.
|
||||||
|
*/
|
||||||
|
inline fun LifecycleOwner?.createDestroyObservable(): Observable<Unit> {
|
||||||
|
return Observable.create { emitter ->
|
||||||
|
if (this == null || this.lifecycle.currentState == Lifecycle.State.DESTROYED) {
|
||||||
|
emitter.onNext(kotlin.Unit)
|
||||||
|
emitter.onComplete()
|
||||||
|
return@create
|
||||||
|
}
|
||||||
|
this.lifecycle.addObserver(object : LifecycleObserver {
|
||||||
|
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||||
|
fun emitDestroy() {
|
||||||
|
if (emitter.isDisposed) {
|
||||||
|
emitter.onNext(kotlin.Unit)
|
||||||
|
emitter.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* 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.mvi
|
||||||
|
|
||||||
|
import io.reactivex.ObservableTransformer
|
||||||
|
import io.reactivex.subjects.Subject
|
||||||
|
import mozilla.components.support.base.log.logger.Logger
|
||||||
|
import org.mozilla.fenix.BuildConfig
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action is a command or intent the user performed
|
||||||
|
*/
|
||||||
|
interface Action
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Change is a change to the view coming from the model
|
||||||
|
* (Extending action so we can reuse the ActionBusFactory)
|
||||||
|
*/
|
||||||
|
interface Change : Action
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ViewState is a model reflecting the current state of the view
|
||||||
|
*/
|
||||||
|
interface ViewState
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Reducer applies changes to the ViewState
|
||||||
|
*/
|
||||||
|
typealias Reducer<S, C> = (S, C) -> S
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple logger for tracking ViewState changes
|
||||||
|
*/
|
||||||
|
fun <S> logState(): ObservableTransformer<S, S> = ObservableTransformer { observable ->
|
||||||
|
observable.doOnNext {
|
||||||
|
if (BuildConfig.DEBUG) Logger("State").debug(it.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For capturing state to a Subject for testing
|
||||||
|
*/
|
||||||
|
fun <S> captureState(subject: Subject<S>):
|
||||||
|
ObservableTransformer<S, S> = ObservableTransformer { observable ->
|
||||||
|
observable.doOnNext {
|
||||||
|
subject.onNext(it)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* 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.mvi
|
||||||
|
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
|
||||||
|
abstract class UIComponent<S: ViewState, A: Action, C: Change>(open val bus: ActionBusFactory) {
|
||||||
|
abstract var initialState: S
|
||||||
|
abstract val reducer: Reducer<S, C>
|
||||||
|
val uiView: UIView<S> by lazy { initView() }
|
||||||
|
|
||||||
|
abstract fun initView(): UIView<S>
|
||||||
|
open fun getContainerId() = uiView.containerId
|
||||||
|
inline fun <reified A: Action> getUserInteractionEvents(): Observable<A> = bus.getSafeManagedObservable(A::class.java)
|
||||||
|
inline fun <reified C: Change> getModelChangeEvents(): Observable<C> = bus.getSafeManagedObservable(C::class.java)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the ViewState to the View through the Reducer
|
||||||
|
*/
|
||||||
|
inline fun <reified C : Change> render(noinline reducer: Reducer<S, C>): Disposable =
|
||||||
|
bus.getSafeManagedObservable(C::class.java)
|
||||||
|
.scan(initialState, reducer)
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(uiView.updateView())
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* 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.mvi
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.annotation.IdRes
|
||||||
|
import io.reactivex.functions.Consumer
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
|
||||||
|
abstract class UIView<S : ViewState>(
|
||||||
|
private val container: ViewGroup, val bus: ActionBusFactory
|
||||||
|
) : LayoutContainer {
|
||||||
|
/**
|
||||||
|
* Get the XML id for the UIView
|
||||||
|
*/
|
||||||
|
@get:IdRes
|
||||||
|
val containerId: Int
|
||||||
|
get() = container.id
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides container to empower Kotlin Android Extensions
|
||||||
|
*/
|
||||||
|
override val containerView: View?
|
||||||
|
get() = container
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the UIView
|
||||||
|
*/
|
||||||
|
open fun show() { container.visibility = View.VISIBLE }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the UIView
|
||||||
|
*/
|
||||||
|
open fun hide() { container.visibility = View.GONE }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the view from the ViewState
|
||||||
|
*/
|
||||||
|
abstract fun updateView(): Consumer<S>
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/session_list"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_margin="16dp"/>
|
|
@ -71,14 +71,4 @@
|
||||||
android:transitionName="firstTransitionName" />
|
android:transitionName="firstTransitionName" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/session_list"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/toolbar_wrapper" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.motion.widget.MotionLayout>
|
</androidx.constraintlayout.motion.widget.MotionLayout>
|
|
@ -6,6 +6,9 @@ private object Versions {
|
||||||
const val kotlin = "1.3.11"
|
const val kotlin = "1.3.11"
|
||||||
const val android_gradle_plugin = "3.2.1"
|
const val android_gradle_plugin = "3.2.1"
|
||||||
const val geckoNightly = "66.0.20190128092811"
|
const val geckoNightly = "66.0.20190128092811"
|
||||||
|
const val rxAndroid = "2.1.0"
|
||||||
|
const val rxKotlin = "2.3.0"
|
||||||
|
const val anko = "0.10.8"
|
||||||
|
|
||||||
const val androidx_appcompat = "1.0.2"
|
const val androidx_appcompat = "1.0.2"
|
||||||
const val androidx_constraint_layout = "2.0.0-alpha3"
|
const val androidx_constraint_layout = "2.0.0-alpha3"
|
||||||
|
@ -26,6 +29,14 @@ object Deps {
|
||||||
const val tools_kotlingradle = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}"
|
const val tools_kotlingradle = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}"
|
||||||
const val kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}"
|
const val kotlin_stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${Versions.kotlin}"
|
||||||
|
|
||||||
|
const val rxKotlin = "io.reactivex.rxjava2:rxkotlin:${Versions.rxKotlin}"
|
||||||
|
const val rxAndroid = "io.reactivex.rxjava2:rxandroid:${Versions.rxAndroid}"
|
||||||
|
|
||||||
|
const val anko_commons = "org.jetbrains.anko:anko-commons:${Versions.anko}"
|
||||||
|
const val anko_sdk = "org.jetbrains.anko:anko-sdk25:${Versions.anko}"
|
||||||
|
const val anko_appcompat = "org.jetbrains.anko:anko-appcompat-v7:${Versions.anko}"
|
||||||
|
const val anko_constraintlayout = "org.jetbrains.anko:anko-constraint-layout:${Versions.anko}"
|
||||||
|
|
||||||
const val geckoview_nightly_arm = "org.mozilla.geckoview:geckoview-nightly-armeabi-v7a:${Versions.geckoNightly}"
|
const val geckoview_nightly_arm = "org.mozilla.geckoview:geckoview-nightly-armeabi-v7a:${Versions.geckoNightly}"
|
||||||
const val geckoview_nightly_x86 = "org.mozilla.geckoview:geckoview-nightly-x86:${Versions.geckoNightly}"
|
const val geckoview_nightly_x86 = "org.mozilla.geckoview:geckoview-nightly-x86:${Versions.geckoNightly}"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue