1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

Tech | Kotlin update + other dependencies (#2079)

This commit is contained in:
Evgenii Kozlov 2022-02-02 21:53:28 +03:00 committed by GitHub
parent 5e5a34f824
commit a0aa9da19d
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 151 additions and 157 deletions

View file

@ -28,6 +28,10 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11
}
}
dependencies {

View file

@ -194,7 +194,7 @@ dependencies {
//Unit/Integration tests dependencies
testImplementation unitTestDependencies.androidXTestCore
testImplementation unitTestDependencies.junit
testImplementation unitTestDependencies.robolectric
testImplementation unitTestDependencies.robolectricLatest
testImplementation unitTestDependencies.kotlinTest
testImplementation unitTestDependencies.mockitoKotlin

View file

@ -1,7 +1,7 @@
apply from: './dependencies.gradle'
buildscript {
ext.kotlin_version = '1.5.21'
ext.kotlin_version = '1.6.10'
ext.gradle_tools = '3.1.3'
ext.build_tools = '31.0.0'
ext.nav_version = '2.3.0'

View file

@ -28,70 +28,70 @@ class SlashWidget @JvmOverloads constructor(
private val mainAdapter by lazy {
SlashMainAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}
private val styleAdapter by lazy {
SlashStyleAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}
private val mediaAdapter by lazy {
SlashMediaAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}
private val objectTypesAdapter by lazy {
SlashObjectTypesAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}
private val relationsAdapter by lazy {
SlashRelationsAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}
private val otherAdapter by lazy {
SlashOtherAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}
private val actionsAdapter by lazy {
SlashActionsAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}
private val alignAdapter by lazy {
SlashAlignmentAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}
private val colorAdapter by lazy {
SlashColorAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}
private val backgroundAdapter by lazy {
SlashColorAdapter(
items = listOf(),
clicks = { _clickEvents.offer(it) }
clicks = { _clickEvents.trySend(it) }
)
}

View file

@ -15,7 +15,7 @@ import kotlinx.coroutines.flow.callbackFlow
fun View.keyboardVisibilityObserver(): Flow<Boolean> = callbackFlow {
val listener = ViewTreeObserver.OnGlobalLayoutListener {
val diff = rootView.height - height
if (diff > context.dp(200f)) offer(true) else offer(false)
if (diff > context.dp(200f)) trySend(true) else trySend(false)
}
viewTreeObserver.addOnGlobalLayoutListener(listener)
awaitClose {

View file

@ -7,56 +7,47 @@ import android.view.MotionEvent
import android.view.View
import android.widget.EditText
import android.widget.TextView
import androidx.annotation.CheckResult
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
@UseExperimental(ExperimentalCoroutinesApi::class)
fun View.clicks(): Flow<Unit> = callbackFlow<Unit> {
fun View.clicks(): Flow<Unit> = callbackFlow {
checkMainThread()
val listener = View.OnClickListener {
safeOffer(Unit)
trySend(Unit)
}
setOnClickListener(listener)
awaitClose { setOnClickListener(null) }
}.conflate()
@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
fun EditText.textChanges(): Flow<CharSequence> = callbackFlow<CharSequence> {
fun EditText.textChanges(): Flow<CharSequence> = callbackFlow {
checkMainThread()
val listener = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
override fun afterTextChanged(s: Editable) = Unit
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
safeOffer(s)
trySend(s)
}
}
addTextChangedListener(listener)
awaitClose { removeTextChangedListener(listener) }
}.conflate()
@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
fun EditText.focusChanges(): Flow<Boolean> = callbackFlow<Boolean> {
fun EditText.focusChanges(): Flow<Boolean> = callbackFlow {
checkMainThread()
val listener = View.OnFocusChangeListener { _, hasFocus -> safeOffer(hasFocus) }
val listener = View.OnFocusChangeListener { _, hasFocus -> trySend(hasFocus) }
onFocusChangeListener = listener
awaitClose { onFocusChangeListener = null }
}.conflate()
@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
fun View.touches(handled: (MotionEvent) -> Boolean = { true }): Flow<MotionEvent> = callbackFlow<MotionEvent> {
checkMainThread()
val listener = View.OnTouchListener { _, event ->
performClick()
if (handled(event)) {
safeOffer(event)
trySend(event)
true
} else {
false
@ -66,39 +57,33 @@ fun View.touches(handled: (MotionEvent) -> Boolean = { true }): Flow<MotionEvent
awaitClose { setOnTouchListener(null) }
}.conflate()
@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
fun EditText.afterTextChanges(): Flow<CharSequence> = callbackFlow<CharSequence> {
checkMainThread()
val listener = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) = Unit
override fun afterTextChanged(s: Editable) {
safeOffer(s.toString())
trySend(s.toString())
}
}
addTextChangedListener(listener)
awaitClose { removeTextChangedListener(listener) }
}.conflate()
@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
fun View.layoutChanges(): Flow<Unit> = callbackFlow {
checkMainThread()
val listener = View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> safeOffer(Unit) }
val listener = View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> trySend(Unit) }
addOnLayoutChangeListener(listener)
awaitClose { removeOnLayoutChangeListener(listener) }
}.conflate()
@CheckResult
@OptIn(ExperimentalCoroutinesApi::class)
fun TextView.editorActionEvents(
handled: (Int) -> Boolean
): Flow<Int> = callbackFlow {
checkMainThread()
val listener = TextView.OnEditorActionListener { _, actionId, _ ->
if (handled(actionId)) {
safeOffer(actionId)
trySend(actionId)
true
} else {
false
@ -108,12 +93,6 @@ fun TextView.editorActionEvents(
awaitClose { setOnEditorActionListener(null) }
}.conflate()
@UseExperimental(ExperimentalCoroutinesApi::class)
fun <E> SendChannel<E>.safeOffer(value: E): Boolean {
return runCatching { offer(value) }.getOrDefault(false)
}
fun checkMainThread() = check(Looper.myLooper() == Looper.getMainLooper()) {
"Expected to be called on the main thread but was " + Thread.currentThread().name
}

View file

@ -29,7 +29,7 @@ class StyleColorToolbarWidget @JvmOverloads constructor(
enabledMarkup = arrayListOf()
) { event ->
Timber.d("Styling Event : $event")
channel.offer(event)
channel.trySend(event)
}
val events = channel.consumeAsFlow()

View file

@ -49,7 +49,7 @@ dependencies {
implementation applicationDependencies.navigation
implementation applicationDependencies.navigationUi
testImplementation unitTestDependencies.robolectric
testImplementation unitTestDependencies.robolectricLatest
androidTestImplementation acceptanceTesting.androidJUnit
androidTestImplementation acceptanceTesting.testRules
testImplementation unitTestDependencies.archCoreTesting

View file

@ -1,7 +1,7 @@
ext {
// Kotlin
kotlin_coroutines_version = '1.5.0'
kotlinx_serialization_json_version = '1.2.1'
kotlin_coroutines_version = '1.6.0'
kotlinx_serialization_json_version = '1.3.1'
// AndroidX
androidx_core_version = '1.7.0'
@ -29,7 +29,7 @@ ext {
glide_version = '4.12.0'
shimmer_layout_version = "0.5.0"
photo_view_version = '2.3.0'
dagger_version = '2.36'
dagger_version = '2.40.5'
javaxAnnotations_version = '1.0'
javaxInject_version = '1'
retrofit_version = '2.3.0'
@ -43,8 +43,7 @@ ext {
katex_version = "1.0.2"
// Unit Testing
robolectric_version = '4.3.1'
robolectric_latest_version = '4.5.1'
robolectric_latest_version = '4.7.3'
junit_version = '4.12'
kluent_version = '1.14'
timber_junit = '1.0.1'
@ -77,7 +76,7 @@ ext {
// DBB
room_version = '2.3.0'
room_version = '2.4.1'
// Analytics
@ -135,7 +134,6 @@ ext {
unitTesting = [
kotlin: "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version",
kotlinTest: "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version",
robolectric: "org.robolectric:robolectric:$robolectric_version",
robolectricLatest: "org.robolectric:robolectric:$robolectric_latest_version",
junit: "junit:junit:$junit_version",
mockitoKotlin: "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version",

View file

@ -52,5 +52,5 @@ dependencies {
testImplementation unitTestDependencies.junit
testImplementation unitTestDependencies.kotlinTest
testImplementation unitTestDependencies.androidXTestCore
testImplementation unitTestDependencies.robolectric
testImplementation unitTestDependencies.robolectricLatest
}

View file

@ -11,7 +11,7 @@ import com.nhaarman.mockitokotlin2.stub
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -49,7 +49,7 @@ class GetProfileTest {
}
@Test
fun `should emit initial data with profile and complete`() = runBlockingTest {
fun `should emit initial data with profile and complete`() = runTest {
val subscription = MockDataFactory.randomUuid()
@ -95,7 +95,7 @@ class GetProfileTest {
}
@Test
fun `should emit transformated profile object, then complete`() = runBlockingTest {
fun `should emit transformated profile object, then complete`() = runTest {
val subscription = MockDataFactory.randomUuid()
@ -167,7 +167,7 @@ class GetProfileTest {
}
@Test
fun `should apply several transformations, then complete`() = runBlockingTest {
fun `should apply several transformations, then complete`() = runTest {
val subscription = MockDataFactory.randomUuid()
@ -247,7 +247,7 @@ class GetProfileTest {
}
@Test
fun `should apply all transformations, then complete`() = runBlockingTest {
fun `should apply all transformations, then complete`() = runTest {
val subscription = MockDataFactory.randomUuid()

View file

@ -11,7 +11,7 @@ import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.stub
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -133,7 +133,7 @@ class ObjectSearchSubscriptionContainerTest {
}
}
runBlockingTest {
runTest {
container.observe(
subscription1,
limit = defaultLimit,

View file

@ -89,6 +89,6 @@ dependencies {
testImplementation unitTestDependencies.junit
testImplementation unitTestDependencies.kotlinTest
testImplementation unitTestDependencies.robolectric
testImplementation unitTestDependencies.robolectricLatest
testImplementation unitTestDependencies.androidXTestCore
}

View file

@ -51,6 +51,6 @@ dependencies {
testImplementation unitTestDependencies.junit
testImplementation unitTestDependencies.kotlinTest
testImplementation unitTestDependencies.robolectric
testImplementation unitTestDependencies.robolectricLatest
testImplementation unitTestDependencies.androidXTestCore
}

View file

@ -19,6 +19,21 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
dependencies {
@ -39,8 +54,6 @@ dependencies {
implementation databaseDependencies.roomKtx
kapt databaseDependencies.annotations
// Current workaround for ROOM on MAC M1 issue.
kapt("org.xerial:sqlite-jdbc:3.34.0")
implementation applicationDependencies.timber

View file

@ -9,14 +9,14 @@ import com.anytypeio.anytype.persistence.model.AccountTable
abstract class AccountDao : BaseDao<AccountTable> {
@Query(Config.CLEAR_ACCOUNT_TABLE)
abstract suspend fun clear()
abstract fun clear()
@Query(Config.QUERY_LAST_ACCOUNT)
abstract suspend fun lastAccount(): List<AccountTable>
abstract fun lastAccount(): List<AccountTable>
@Query(Config.QUERY_ACCOUNT_BY_ID)
abstract suspend fun getAccount(id: String): AccountTable?
abstract fun getAccount(id: String): AccountTable?
@Query(Config.GET_ACCOUNTS)
abstract suspend fun getAccounts(): List<AccountTable>
abstract fun getAccounts(): List<AccountTable>
}

View file

@ -11,7 +11,7 @@ interface BaseDao<T> {
* @param obj the object to be inserted.
*/
@Insert
suspend fun insert(obj: T)
fun insert(obj: T)
/**
* Insert an array of objects in the database.
@ -19,7 +19,7 @@ interface BaseDao<T> {
* @param obj the objects to be inserted.
*/
@Insert
suspend fun insert(objects: List<T>)
fun insert(objects: List<T>)
/**
* Update an object from the database.
@ -27,7 +27,7 @@ interface BaseDao<T> {
* @param obj the object to be updated
*/
@Update
suspend fun update(obj: T)
fun update(obj: T)
/**
* Delete an object from the database
@ -35,5 +35,5 @@ interface BaseDao<T> {
* @param obj the object to be deleted
*/
@Delete
suspend fun delete(obj: T)
fun delete(obj: T)
}

View file

@ -1,85 +1,85 @@
package com.anytypeio.anytype
//import androidx.arch.core.executor.testing.InstantTaskExecutorRule
//import androidx.room.Room
//import androidx.test.platform.app.InstrumentationRegistry
//import com.anytypeio.anytype.persistence.db.AnytypeDatabase
//import com.anytypeio.anytype.persistence.model.AccountTable
//import kotlinx.coroutines.delay
//import kotlinx.coroutines.runBlocking
//import org.junit.After
//import org.junit.Rule
//import org.junit.Test
//import org.junit.runner.RunWith
//import org.robolectric.RobolectricTestRunner
//import org.robolectric.annotation.Config
//import kotlin.test.assertEquals
//import kotlin.test.assertTrue
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.room.Room
import androidx.test.platform.app.InstrumentationRegistry
import com.anytypeio.anytype.persistence.db.AnytypeDatabase
import com.anytypeio.anytype.persistence.model.AccountTable
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.test.assertEquals
import kotlin.test.assertTrue
//@RunWith(RobolectricTestRunner::class)
//@Config(manifest = Config.NONE)
//class AccountDaoTest {
//
// @get:Rule
// val instantTaskExecutorRule = InstantTaskExecutorRule()
//
// private val database = Room.inMemoryDatabaseBuilder(
// InstrumentationRegistry.getInstrumentation().context,
// AnytypeDatabase::class.java
// ).allowMainThreadQueries().build()
//
// @After
// fun after() {
// database.close()
// }
//
// @Test
// fun `should return empty list if there are no last account in db`() {
// runBlocking {
// val accounts = database.accountDao().lastAccount()
// assertTrue { accounts.isEmpty() }
// }
// }
//
// @Test
// fun `should return last account`() = runBlocking {
//
// val firstAccount = AccountTable(
// id = MockDataFactory.randomString(),
// name = MockDataFactory.randomString(),
// timestamp = System.currentTimeMillis()
// )
//
// delay(1)
//
// val secondAccount = AccountTable(
// id = MockDataFactory.randomString(),
// name = MockDataFactory.randomString(),
// timestamp = System.currentTimeMillis()
// )
//
// database.accountDao().insert(firstAccount)
// database.accountDao().insert(secondAccount)
//
// val result = database.accountDao().lastAccount()
//
// assertTrue { result.size == 1 }
// assertTrue { result.first() == secondAccount }
// }
//
// @Test
// fun `should return expected account when queried using account id`() = runBlocking {
//
// val account = AccountTable(
// id = MockDataFactory.randomString(),
// name = MockDataFactory.randomString(),
// timestamp = System.currentTimeMillis()
// )
//
// database.accountDao().insert(account)
//
// val result = database.accountDao().getAccount(account.id)
//
// assertEquals(account, result)
// }
//}
@RunWith(RobolectricTestRunner::class)
@Config(manifest = Config.NONE)
class AccountDaoTest {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
private val database = Room.inMemoryDatabaseBuilder(
InstrumentationRegistry.getInstrumentation().context,
AnytypeDatabase::class.java
).allowMainThreadQueries().build()
@After
fun after() {
database.close()
}
@Test
fun `should return empty list if there are no last account in db`() {
runBlocking {
val accounts = database.accountDao().lastAccount()
assertTrue { accounts.isEmpty() }
}
}
@Test
fun `should return last account`() = runBlocking {
val firstAccount = AccountTable(
id = MockDataFactory.randomString(),
name = MockDataFactory.randomString(),
timestamp = System.currentTimeMillis()
)
delay(1)
val secondAccount = AccountTable(
id = MockDataFactory.randomString(),
name = MockDataFactory.randomString(),
timestamp = System.currentTimeMillis()
)
database.accountDao().insert(firstAccount)
database.accountDao().insert(secondAccount)
val result = database.accountDao().lastAccount()
assertTrue { result.size == 1 }
assertTrue { result.first() == secondAccount }
}
@Test
fun `should return expected account when queried using account id`() = runBlocking {
val account = AccountTable(
id = MockDataFactory.randomString(),
name = MockDataFactory.randomString(),
timestamp = System.currentTimeMillis()
)
database.accountDao().insert(account)
val result = database.accountDao().getAccount(account.id)
assertEquals(account, result)
}
}

View file

@ -121,7 +121,7 @@ class ObjectSetViewModel(
init {
viewModelScope.launch {
dispatcher.flow().collect(defaultPayloadConsumer)
dispatcher.flow().collect { defaultPayloadConsumer(it) }
}
viewModelScope.launch {