1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-11-23 11:16:08 -06:00

Refactor main module (#154)

This commit is contained in:
Rafał Borcz 2018-08-24 15:48:29 +02:00 committed by Mikołaj Pich
parent a90d5cb9c3
commit 0e962c17c2
26 changed files with 433 additions and 97 deletions

View File

@ -113,7 +113,6 @@ dependencies {
implementation "org.apache.commons:commons-collections4:$apacheCollections"
implementation "eu.davidea:flexible-adapter:$flexibleAdapter"
implementation "eu.davidea:flexible-adapter-ui:$flexibleUi"
implementation "com.jakewharton:butterknife:$butterknife"
implementation "com.google.dagger:dagger-android-support:$dagger2"
implementation "com.aurelhubert:ahbottomnavigation:$ahbottom"
implementation "com.jakewharton.threetenabp:threetenabp:$threeTenABP"
@ -126,6 +125,7 @@ dependencies {
implementation 'com.android.support:multidex:1.0.3'
implementation "android.arch.persistence.room:rxjava2:1.1.1"
implementation 'com.github.pwittchen:reactivenetwork-rx2:2.1.0'
implementation 'com.ncapdevi:frag-nav:3.0.0-RC3'
implementation("com.crashlytics.sdk.android:crashlytics:$crashlyticsSdk@aar") {
transitive = true
@ -136,7 +136,6 @@ dependencies {
kapt "com.google.dagger:dagger-compiler:$dagger2"
kapt "com.google.dagger:dagger-android-processor:$dagger2"
kapt "com.jakewharton:butterknife-compiler:$butterknife"
kapt "android.arch.persistence.room:compiler:1.1.1"
debugImplementation "com.amitshekhar.android:debug-db:$debugDb"

View File

@ -20,16 +20,18 @@ task jacocoTestReport(type: JacocoReport) {
html.enabled = true
}
def excludes = [
"**/R.class",
"**/R\$*.class",
"**/*\$ViewInjector*.*",
"**/BuildConfig.*",
"**/Manifest*.*",
"**/*Test*.*",
"android/**/*.*",
"**/*Fragment.*",
"**/*Activity.*"
def excludes = ['**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'android/**/*.*',
'**/*Module.*',
'**/*Dagger*.*',
'**/*MembersInjector*.*',
'**/*_Provide*Factory*.*',
'**/*_Factory.*',
'**/*$*$*.*'
]
// generated classes
@ -43,14 +45,9 @@ task jacocoTestReport(type: JacocoReport) {
excludes: excludes
)
// sources
sourceDirectories = files([
android.sourceSets.main.java.srcDirs,
"src/main/kotlin"
])
sourceDirectories = files("$project.projectDir/src/main/java")
executionData = fileTree(
dir: project.projectDir,
includes: ["**/*.exec" , "**/*.ec"]
includes: ["**/*.exec", "**/*.ec"]
)
}

View File

@ -34,7 +34,7 @@
<activity
android:name=".ui.main.MainActivity"
android:configChanges="orientation|screenSize"
android:label="@string/activity_dashboard_text"
android:label="@string/activity_main_text"
android:launchMode="singleTop" />
<activity
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"

View File

@ -6,6 +6,7 @@ import io.github.wulkanowy.di.scopes.PerActivity
import io.github.wulkanowy.ui.login.LoginActivity
import io.github.wulkanowy.ui.login.LoginModule
import io.github.wulkanowy.ui.main.MainActivity
import io.github.wulkanowy.ui.main.MainModule
import io.github.wulkanowy.ui.splash.SplashActivity
@Module
@ -20,6 +21,6 @@ internal abstract class BuilderModule {
abstract fun bindLoginActivity(): LoginActivity
@PerActivity
@ContributesAndroidInjector()
@ContributesAndroidInjector(modules = [MainModule::class])
abstract fun bindMainActivity(): MainActivity
}

View File

@ -4,6 +4,8 @@ import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
@ -57,8 +59,8 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView {
}
override fun showLoginProgress(show: Boolean) {
loginOptionsProgressContainer.visibility = if (show) View.GONE else View.VISIBLE
loginOptionsRecycler.visibility = if (show) View.VISIBLE else View.GONE
loginOptionsProgressContainer.visibility = if (show) VISIBLE else GONE
loginOptionsRecycler.visibility = if (show) GONE else VISIBLE
}
override fun showActionBar(show: Boolean) {

View File

@ -37,7 +37,10 @@ class LoginOptionsPresenter @Inject constructor(
Single.fromCallable { repository.save(it) }
.subscribeOn(schedulers.backgroundThread())
.observeOn(schedulers.mainThread())
.doOnSubscribe { _ -> view?.showLoginProgress(true) }
.doOnSubscribe { _ ->
view?.showLoginProgress(true)
view?.showActionBar(false)
}
.doOnSuccess { _ -> view?.openMainView() }
.subscribe({ _ -> }, { error -> errorHandler.proceed(error) })
})

View File

@ -2,12 +2,107 @@ package io.github.wulkanowy.ui.main
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import com.aurelhubert.ahbottomnavigation.AHBottomNavigation
import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem
import com.ncapdevi.fragnav.FragNavController
import com.ncapdevi.fragnav.FragNavController.Companion.DETACH_ON_NAVIGATE_HIDE_ON_SWITCH
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.main.attendance.AttendanceFragment
import io.github.wulkanowy.ui.main.exam.ExamFragment
import io.github.wulkanowy.ui.main.grade.GradeFragment
import io.github.wulkanowy.ui.main.more.MoreFragment
import io.github.wulkanowy.ui.main.timetable.TimetableFragment
import kotlinx.android.synthetic.main.activity_main.*
import javax.inject.Inject
class MainActivity : BaseActivity() {
class MainActivity : BaseActivity(), MainView, FragNavController.TransactionListener {
@Inject
lateinit var presenter: MainPresenter
@Inject
lateinit var navController: FragNavController
companion object {
const val DEFAULT_TAB = 0
fun getStartIntent(context: Context) = Intent(context, MainActivity::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
messageView = mainContainer
presenter.attachView(this)
navController.initialize(DEFAULT_TAB, savedInstanceState)
}
override fun initFragmentController() {
navController.run {
rootFragments = listOf(
GradeFragment.newInstance(),
AttendanceFragment.newInstance(),
ExamFragment.newInstance(),
TimetableFragment.newInstance(),
MoreFragment.newInstance()
)
fragmentHideStrategy = DETACH_ON_NAVIGATE_HIDE_ON_SWITCH
createEager = true
transactionListener = this@MainActivity
}
}
override fun initBottomNav() {
mainBottomNav.run {
addItems(mutableListOf(
AHBottomNavigationItem(R.string.grades_text, R.drawable.ic_menu_grade_26dp, 0),
AHBottomNavigationItem(R.string.attendance_text, R.drawable.ic_menu_attendance_24dp, 0),
AHBottomNavigationItem(R.string.exams_text, R.drawable.ic_menu_exams_24dp, 0),
AHBottomNavigationItem(R.string.timetable_text, R.drawable.ic_menu_timetable_24dp, 0),
AHBottomNavigationItem(R.string.more_text, R.drawable.ic_menu_other_24dp, 0)
))
accentColor = ContextCompat.getColor(context, R.color.colorPrimary)
inactiveColor = ContextCompat.getColor(context, android.R.color.black)
titleState = AHBottomNavigation.TitleState.ALWAYS_SHOW
currentItem = DEFAULT_TAB
isBehaviorTranslationEnabled = false
setOnTabSelectedListener { position, _ ->
presenter.onTabSelected(position)
}
}
}
override fun onFragmentTransaction(fragment: Fragment?, transactionType: FragNavController.TransactionType) {}
override fun onTabTransaction(fragment: Fragment?, index: Int) {
presenter.onMenuFragmentChange(index)
}
override fun switchMenuFragment(position: Int) {
navController.switchTab(position)
}
override fun setViewTitle(title: String) {
setTitle(title)
}
override fun defaultTitle(): String = getString(R.string.activity_main_text)
override fun mapOfTitles(): Map<Int, String> {
return mapOf(0 to R.string.grades_text,
1 to R.string.attendance_text,
2 to R.string.exams_text,
3 to R.string.timetable_text,
4 to R.string.more_text
).mapValues { getString(it.value) }
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
navController.onSaveInstanceState(outState)
}
}

View File

@ -0,0 +1,50 @@
package io.github.wulkanowy.ui.main
import com.ncapdevi.fragnav.FragNavController
import dagger.Module
import dagger.Provides
import dagger.android.ContributesAndroidInjector
import io.github.wulkanowy.R
import io.github.wulkanowy.di.scopes.PerActivity
import io.github.wulkanowy.di.scopes.PerFragment
import io.github.wulkanowy.ui.main.attendance.AttendanceFragment
import io.github.wulkanowy.ui.main.exam.ExamFragment
import io.github.wulkanowy.ui.main.grade.GradeFragment
import io.github.wulkanowy.ui.main.more.MoreFragment
import io.github.wulkanowy.ui.main.timetable.TimetableFragment
@Module
abstract class MainModule {
@Module
companion object {
@JvmStatic
@PerActivity
@Provides
fun provideFragNavController(activity: MainActivity): FragNavController {
return FragNavController(activity.supportFragmentManager, R.id.mainFragmentContainer)
}
}
@PerFragment
@ContributesAndroidInjector
abstract fun bindAttendanceFragment(): AttendanceFragment
@PerFragment
@ContributesAndroidInjector
abstract fun bindExamFragment(): ExamFragment
@PerFragment
@ContributesAndroidInjector
abstract fun bindGradeFragment(): GradeFragment
@PerFragment
@ContributesAndroidInjector
abstract fun bindMoreFragment(): MoreFragment
@PerFragment
@ContributesAndroidInjector
abstract fun bindTimetableFragment(): TimetableFragment
}

View File

@ -0,0 +1,29 @@
package io.github.wulkanowy.ui.main
import io.github.wulkanowy.data.ErrorHandler
import io.github.wulkanowy.ui.base.BasePresenter
import javax.inject.Inject
class MainPresenter @Inject constructor(errorHandler: ErrorHandler)
: BasePresenter<MainView>(errorHandler) {
override fun attachView(view: MainView) {
super.attachView(view)
view.run {
initFragmentController()
initBottomNav()
}
}
fun onTabSelected(position: Int): Boolean {
view?.switchMenuFragment(position)
return true
}
fun onMenuFragmentChange(position: Int) {
view?.run {
setViewTitle(mapOfTitles()[position] ?: defaultTitle())
}
}
}

View File

@ -0,0 +1,18 @@
package io.github.wulkanowy.ui.main
import io.github.wulkanowy.ui.base.BaseView
interface MainView : BaseView {
fun initFragmentController()
fun initBottomNav()
fun switchMenuFragment(position: Int)
fun setViewTitle(title: String)
fun defaultTitle(): String
fun mapOfTitles(): Map<Int, String>
}

View File

@ -0,0 +1,20 @@
package io.github.wulkanowy.ui.main.attendance
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseFragment
class AttendanceFragment : BaseFragment() {
companion object {
fun newInstance() = AttendanceFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_attendance, container, false)
}
}

View File

@ -0,0 +1,20 @@
package io.github.wulkanowy.ui.main.exam
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseFragment
class ExamFragment : BaseFragment() {
companion object {
fun newInstance() = ExamFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_exams, container, false)
}
}

View File

@ -0,0 +1,20 @@
package io.github.wulkanowy.ui.main.grade
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseFragment
class GradeFragment : BaseFragment() {
companion object {
fun newInstance() = GradeFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_grades, container, false)
}
}

View File

@ -0,0 +1,20 @@
package io.github.wulkanowy.ui.main.more
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseFragment
class MoreFragment : BaseFragment() {
companion object {
fun newInstance() = MoreFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_timetable, container, false)
}
}

View File

@ -0,0 +1,20 @@
package io.github.wulkanowy.ui.main.timetable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseFragment
class TimetableFragment : BaseFragment() {
companion object {
fun newInstance() = TimetableFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_timetable, container, false)
}
}

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.splash
import android.os.Bundle
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.login.LoginActivity
import io.github.wulkanowy.ui.main.MainActivity
import javax.inject.Inject
class SplashActivity : BaseActivity(), SplashView {
@ -26,7 +27,7 @@ class SplashActivity : BaseActivity(), SplashView {
}
override fun openMainActivity() {
//TODO('Not implemented)
startActivity(MainActivity.getStartIntent(this))
finish()
}
}

View File

@ -1,53 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_activity_container"
android:id="@+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:weightSum="1">
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<FrameLayout
android:id="@+id/mainFragmentContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<android.support.design.widget.AppBarLayout
android:id="@+id/main_activity_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/main_activity_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
<RelativeLayout
android:id="@+id/main_activity_progress_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</RelativeLayout>
<com.aurelhubert.ahbottomnavigation.AHBottomNavigationViewPager
android:id="@+id/main_activity_view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/bottom_navigation_height"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
android:id="@+id/main_activity_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
</android.support.design.widget.CoordinatorLayout>
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
android:id="@+id/mainBottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
</LinearLayout>

View File

@ -1,11 +1,16 @@
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/attendanceContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:id="@+id/attendance_fragment_container">
android:layout_alignParentBottom="true">
<RelativeLayout
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Attendance" />
<!--<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -21,5 +26,5 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/attendance_fragment_tab_layout" />
</RelativeLayout>
</RelativeLayout>-->
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,11 +1,16 @@
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/exams_fragment_container"
android:id="@+id/examContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true">
<RelativeLayout
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Exam" />
<!--<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -21,5 +26,5 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/exams_fragment_tab_layout" />
</RelativeLayout>
</RelativeLayout>-->
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,12 +1,15 @@
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/grade_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="io.github.wulkanowy.ui.main.grades.GradesFragment">
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Grade" />
<!--<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/grade_fragment_swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -167,5 +170,5 @@
android:textSize="20sp" />
</RelativeLayout>
</FrameLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.v4.widget.SwipeRefreshLayout>-->
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,11 +1,16 @@
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/timetable_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:id="@+id/timetable_fragment_container">
android:layout_alignParentBottom="true">
<RelativeLayout
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="Timetable" />
<!--<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -21,5 +26,5 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/timetable_fragment_tab_layout" />
</RelativeLayout>
</RelativeLayout>-->
</android.support.design.widget.CoordinatorLayout>

View File

@ -32,12 +32,13 @@
<string name="color_green_text">Zielony</string>
<string name="noColor_text">Brak koloru</string>
<string name="activity_dashboard_text">Aktywność dashboard</string>
<string name="activity_main_text">Główna aktywność</string>
<string name="exams_text">Sprawdziany</string>
<string name="grades_text">Oceny</string>
<string name="attendance_text">Frekwencja</string>
<string name="timetable_text">Plan lekcji</string>
<string name="settings_text">Ustawienia</string>
<string name="more_text">Więcej</string>
<string name="activity_under_construction">Ta część aplikacji jest w budowie</string>
<string name="fragment_no_grades">Brak ocen</string>

View File

@ -32,12 +32,13 @@
<string name="color_green_text">Green</string>
<string name="noColor_text">No color</string>
<string name="activity_dashboard_text">Dashboard Activity</string>
<string name="activity_main_text">Main Activity</string>
<string name="exams_text">Exams</string>
<string name="grades_text">Grades</string>
<string name="attendance_text">Attendance</string>
<string name="timetable_text">Timetable</string>
<string name="settings_text">Settings</string>
<string name="more_text">More</string>
<string name="activity_under_construction">This section of app is under construction.</string>
<string name="fragment_no_grades">No grades</string>

View File

@ -1,6 +1,6 @@
<resources>
<style name="WulkanowyTheme" parent="@style/Theme.AppCompat.DayNight.NoActionBar">
<style name="WulkanowyTheme" parent="@style/Theme.AppCompat.DayNight">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorPrimary</item>

View File

@ -0,0 +1,55 @@
package io.github.wulkanowy.ui.main
import io.github.wulkanowy.data.ErrorHandler
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.MockitoAnnotations
class MainPresenterTest {
@Mock
lateinit var errorHandler: ErrorHandler
@Mock
lateinit var mainView: MainView
private lateinit var presenter: MainPresenter
@Before
fun initPresenter() {
MockitoAnnotations.initMocks(this)
clearInvocations(mainView)
presenter = MainPresenter(errorHandler)
presenter.attachView(mainView)
}
@Test
fun initMenuTest() {
verify(mainView).initBottomNav()
verify(mainView).initFragmentController()
}
@Test
fun onTabSelectedTest() {
presenter.onTabSelected(1)
verify(mainView).switchMenuFragment(1)
}
@Test
fun onMenuFragmentChangeTest() {
doReturn(mapOf(1 to "Test")).`when`(mainView).mapOfTitles()
presenter.onMenuFragmentChange(1)
verify(mainView).setViewTitle("Test")
}
@Test
fun onMenuFragmentChangeDefaultTest() {
doReturn(emptyMap<Int, String>()).`when`(mainView).mapOfTitles()
doReturn("Default").`when`(mainView).defaultTitle()
presenter.onMenuFragmentChange(2)
verify(mainView).setViewTitle("Default")
}
}

View File

@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.2.60'
ext.kotlin_version = '1.2.61'
repositories {
mavenCentral()
google()
@ -44,7 +44,7 @@ ext {
apacheCollections = "4.2"
butterknife = "8.8.1"
threeTenABP = "1.1.0"
dagger2 = "2.16"
dagger2 = "2.17"
ahbottom = "2.2.0"
jsoup = "1.11.3"
gson = "2.8.5"