update dependencies, migrate code & cleanup (#12)

* update dependencies, migrate code & cleanup

* migrate from Kotlin Android extensions to Kotlin Parcelize

* fix import order
This commit is contained in:
Konrad Pozniak 2022-01-30 21:49:38 +01:00 committed by GitHub
parent 7c14af603e
commit 466dba6096
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 133 additions and 162 deletions

View File

@ -1,16 +1,16 @@
plugins { plugins {
id("com.android.application") id("com.android.application")
id("kotlin-android") id("kotlin-android")
id("kotlin-android-extensions")
id("kotlin-kapt") id("kotlin-kapt")
id("kotlin-parcelize")
} }
android { android {
compileSdkVersion(30) compileSdk = 31
defaultConfig { defaultConfig {
applicationId = "at.connyduck.pixelcat" applicationId = "at.connyduck.pixelcat"
minSdkVersion(24) minSdk = 24
targetSdkVersion(30) targetSdk = 31
versionCode = 1 versionCode = 1
versionName = "0.0 snapshot1" versionName = "0.0 snapshot1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@ -29,19 +29,15 @@ android {
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
androidExtensions {
features = setOf("parcelize")
}
buildFeatures { buildFeatures {
viewBinding = true viewBinding = true
} }
packagingOptions { packagingOptions {
exclude("LICENSE_OFL") resources.excludes.add("LICENSE_OFL")
exclude("LICENSE_UNICODE") resources.excludes.add("LICENSE_UNICODE")
exclude("okhttp3/internal/publicsuffix/NOTICE") resources.excludes.add("okhttp3/internal/publicsuffix/NOTICE")
exclude("DebugProbesKt.bin") resources.excludes.add("DebugProbesKt.bin")
} }
sourceSets["main"].java.srcDir("src/main/kotlin") sourceSets["main"].java.srcDir("src/main/kotlin")
@ -60,37 +56,36 @@ tasks {
dependencies { dependencies {
val lifecycleVersion = "2.3.0-alpha07" val lifecycleVersion = "2.4.0"
val emojiCompatVersion = "1.2.0-alpha01" val emojiCompatVersion = "1.2.0-alpha01"
val roomVersion = "2.3.0-alpha03" val roomVersion = "2.4.1"
val okHttpVersion = "4.8.1" val okHttpVersion = "4.9.3"
val retrofitVersion = "2.9.0" val retrofitVersion = "2.9.0"
val moshiVersion = "1.10.0" val moshiVersion = "1.13.0"
val daggerVersion = "2.28.3" val daggerVersion = "2.40.5"
val jUnitVersion = "5.7.0" val jUnitVersion = "5.8.2"
implementation(kotlin("stdlib-jdk7")) implementation("androidx.core:core-ktx:1.7.0")
implementation("androidx.appcompat:appcompat:1.4.1")
implementation("androidx.core:core-ktx:1.5.0-alpha03") implementation("androidx.activity:activity-ktx:1.4.0")
implementation("androidx.appcompat:appcompat:1.3.0-alpha02") implementation("androidx.fragment:fragment-ktx:1.4.1")
implementation("androidx.activity:activity-ktx:1.2.0-alpha08") implementation("com.google.android.material:material:1.5.0")
implementation("androidx.fragment:fragment-ktx:1.3.0-alpha08") implementation("androidx.constraintlayout:constraintlayout:2.1.3")
implementation("com.google.android.material:material:1.3.0-alpha02")
implementation("androidx.constraintlayout:constraintlayout:2.0.1")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.recyclerview:recyclerview:1.2.0-alpha05") implementation("androidx.recyclerview:recyclerview:1.2.1")
implementation("androidx.annotation:annotation:1.1.0") implementation("androidx.annotation:annotation:1.3.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion") implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion") implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion")
implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion") implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion")
implementation("androidx.preference:preference:1.1.1") implementation("androidx.preference:preference-ktx:1.2.0")
implementation("androidx.emoji:emoji-bundled:$emojiCompatVersion") implementation("androidx.emoji:emoji-bundled:$emojiCompatVersion")
implementation("androidx.emoji:emoji-appcompat:$emojiCompatVersion") implementation("androidx.emoji:emoji-appcompat:$emojiCompatVersion")
implementation("androidx.paging:paging-runtime-ktx:3.0.0-alpha06") implementation("androidx.paging:paging-runtime-ktx:3.1.0")
implementation("androidx.viewpager2:viewpager2:1.0.0") implementation("androidx.viewpager2:viewpager2:1.0.0")
implementation("androidx.room:room-ktx:$roomVersion") implementation("androidx.room:room-ktx:$roomVersion")
implementation("androidx.room:room-paging:$roomVersion")
kapt("androidx.room:room-compiler:$roomVersion") kapt("androidx.room:room-compiler:$roomVersion")
implementation("com.squareup.okhttp3:okhttp:$okHttpVersion") implementation("com.squareup.okhttp3:okhttp:$okHttpVersion")
@ -103,17 +98,17 @@ dependencies {
implementation("com.squareup.moshi:moshi-adapters:$moshiVersion") implementation("com.squareup.moshi:moshi-adapters:$moshiVersion")
kapt("com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion") kapt("com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
implementation("com.fxn769:pix:1.4.4") implementation("com.fxn769:pix:1.5.6")
implementation("com.github.yalantis:ucrop:2.2.5") implementation("com.github.yalantis:ucrop:2.2.5")
implementation("me.relex:circleindicator:2.1.4") implementation("me.relex:circleindicator:2.1.6")
implementation("io.coil-kt:coil:1.0.0-rc3") implementation("io.coil-kt:coil:1.0.0-rc3")
implementation("com.github.connyduck:sparkbutton:4.0.0") implementation("com.github.connyduck:sparkbutton:4.1.0")
implementation("com.google.dagger:dagger:$daggerVersion") implementation("com.google.dagger:dagger:$daggerVersion")
kapt("com.google.dagger:dagger-compiler:$daggerVersion") kapt("com.google.dagger:dagger-compiler:$daggerVersion")

View File

@ -17,7 +17,8 @@
android:usesCleartextTraffic="false" android:usesCleartextTraffic="false"
tools:ignore="AllowBackup,GoogleAppIndexingWarning"> tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<!-- TODO order activities --> <!-- TODO order activities -->
<activity android:name=".components.splash.SplashActivity"> <activity android:name=".components.splash.SplashActivity"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>

View File

@ -37,7 +37,6 @@ import at.connyduck.pixelcat.databinding.ActivityComposeBinding
import at.connyduck.pixelcat.util.viewBinding import at.connyduck.pixelcat.util.viewBinding
import com.fxn.pix.Options import com.fxn.pix.Options
import com.fxn.pix.Pix import com.fxn.pix.Pix
import com.fxn.utility.ImageQuality
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@ -104,24 +103,23 @@ class ComposeActivity : BaseActivity(), OnImageActionClickListener {
} }
viewModel.imageLiveData.observe( viewModel.imageLiveData.observe(
this, this
{ ) {
adapter.submitList(it) adapter.submitList(it)
} }
)
viewModel.visibility.observe( viewModel.visibility.observe(
this, this
{ ) {
val visibilityString = when (it) { val visibilityString = when (it) {
VISIBILITY.PUBLIC -> R.string.compose_visibility_public VISIBILITY.PUBLIC -> R.string.compose_visibility_public
VISIBILITY.UNLISTED -> R.string.compose_visibility_unlisted VISIBILITY.UNLISTED -> R.string.compose_visibility_unlisted
VISIBILITY.FOLLOWERS_ONLY -> R.string.compose_visibility_followers_only VISIBILITY.FOLLOWERS_ONLY -> R.string.compose_visibility_followers_only
}
binding.composeVisibilityButton.text = getString(R.string.compose_visibility, getString(visibilityString))
} }
)
binding.composeVisibilityButton.text =
getString(R.string.compose_visibility, getString(visibilityString))
}
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -141,7 +139,6 @@ class ComposeActivity : BaseActivity(), OnImageActionClickListener {
override fun onAddImage() { override fun onAddImage() {
val options = Options.init() val options = Options.init()
.setRequestCode(REQUEST_CODE_PICK_MEDIA) .setRequestCode(REQUEST_CODE_PICK_MEDIA)
.setImageQuality(ImageQuality.HIGH)
.setScreenOrientation(Options.SCREEN_ORIENTATION_PORTRAIT) .setScreenOrientation(Options.SCREEN_ORIENTATION_PORTRAIT)
Pix.start(this, options) Pix.start(this, options)

View File

@ -38,13 +38,13 @@ import at.connyduck.pixelcat.model.NewStatus
import at.connyduck.pixelcat.network.FediverseApi import at.connyduck.pixelcat.network.FediverseApi
import at.connyduck.pixelcat.network.calladapter.NetworkResponseError import at.connyduck.pixelcat.network.calladapter.NetworkResponseError
import dagger.android.DaggerService import dagger.android.DaggerService
import kotlinx.android.parcel.Parcelize
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.asRequestBody

View File

@ -43,14 +43,9 @@ import at.connyduck.pixelcat.components.util.extension.visible
import at.connyduck.pixelcat.dagger.ViewModelFactory import at.connyduck.pixelcat.dagger.ViewModelFactory
import at.connyduck.pixelcat.databinding.ActivityLoginBinding import at.connyduck.pixelcat.databinding.ActivityLoginBinding
import at.connyduck.pixelcat.util.viewBinding import at.connyduck.pixelcat.util.viewBinding
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@FlowPreview
@ExperimentalCoroutinesApi
class LoginActivity : BaseActivity() { class LoginActivity : BaseActivity() {
@Inject @Inject

View File

@ -20,7 +20,7 @@
package at.connyduck.pixelcat.components.login package at.connyduck.pixelcat.components.login
import android.os.Parcelable import android.os.Parcelable
import kotlinx.android.parcel.Parcelize import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
data class LoginModel( data class LoginModel(

View File

@ -25,25 +25,21 @@ import at.connyduck.pixelcat.config.Config
import at.connyduck.pixelcat.db.AccountManager import at.connyduck.pixelcat.db.AccountManager
import at.connyduck.pixelcat.db.entitity.AccountAuthData import at.connyduck.pixelcat.db.entitity.AccountAuthData
import at.connyduck.pixelcat.network.FediverseApi import at.connyduck.pixelcat.network.FediverseApi
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.HttpUrl import okhttp3.HttpUrl
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@FlowPreview
@ExperimentalCoroutinesApi
class LoginViewModel @Inject constructor( class LoginViewModel @Inject constructor(
private val api: FediverseApi, private val api: FediverseApi,
private val accountManager: AccountManager private val accountManager: AccountManager
) : ViewModel() { ) : ViewModel() {
private val loginState = ConflatedBroadcastChannel(LoginModel(state = LoginState.NO_ERROR)) private val loginState = MutableStateFlow(LoginModel(state = LoginState.NO_ERROR))
fun observe() = loginState.asFlow() fun observe(): Flow<LoginModel> = loginState
fun startLogin(input: String) { fun startLogin(input: String) {
viewModelScope.launch { viewModelScope.launch {
@ -52,7 +48,7 @@ class LoginViewModel @Inject constructor(
try { try {
HttpUrl.Builder().host(domainInput).scheme("https").build() HttpUrl.Builder().host(domainInput).scheme("https").build()
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
loginState.send(LoginModel(input, LoginState.INVALID_DOMAIN)) loginState.value = LoginModel(input, LoginState.INVALID_DOMAIN)
return@launch return@launch
} }
@ -61,11 +57,11 @@ class LoginViewModel @Inject constructor(
} }
if (exceptionMatch) { if (exceptionMatch) {
loginState.send(LoginModel(input, LoginState.AUTH_ERROR)) loginState.value = LoginModel(input, LoginState.AUTH_ERROR)
return@launch return@launch
} }
loginState.send(LoginModel(input, LoginState.LOADING)) loginState.value = LoginModel(input, LoginState.LOADING)
api.authenticateAppAsync( api.authenticateAppAsync(
domain = domainInput, domain = domainInput,
@ -75,10 +71,10 @@ class LoginViewModel @Inject constructor(
scopes = Config.oAuthScopes scopes = Config.oAuthScopes
).fold( ).fold(
{ appData -> { appData ->
loginState.send(LoginModel(input, LoginState.SUCCESS, domainInput, appData.clientId, appData.clientSecret)) loginState.value = LoginModel(input, LoginState.SUCCESS, domainInput, appData.clientId, appData.clientSecret)
}, },
{ {
loginState.send(LoginModel(input, LoginState.AUTH_ERROR)) loginState.value = LoginModel(input, LoginState.AUTH_ERROR)
} }
) )
} }
@ -107,19 +103,17 @@ class LoginViewModel @Inject constructor(
clientSecret = loginModel.clientSecret clientSecret = loginModel.clientSecret
) )
accountManager.addAccount(loginModel.domain, authData) accountManager.addAccount(loginModel.domain, authData)
loginState.send(loginState.value.copy(state = LoginState.SUCCESS_FINAL)) loginState.value = loginState.value.copy(state = LoginState.SUCCESS_FINAL)
}, },
{ {
loginState.send(loginState.value.copy(state = LoginState.AUTH_ERROR)) loginState.value = loginState.value.copy(state = LoginState.AUTH_ERROR)
} }
) )
} }
} }
fun removeError() { fun removeError() {
viewModelScope.launch { loginState.value = loginState.value.copy(state = LoginState.NO_ERROR)
loginState.send(loginState.value.copy(state = LoginState.NO_ERROR))
}
} }
private fun canonicalizeDomain(domain: String): String { private fun canonicalizeDomain(domain: String): String {
@ -131,6 +125,6 @@ class LoginViewModel @Inject constructor(
if (at != -1) { if (at != -1) {
s = s.substring(at + 1) s = s.substring(at + 1)
} }
return s.trim().toLowerCase(Locale.ROOT) return s.trim().lowercase(Locale.ROOT)
} }
} }

View File

@ -35,8 +35,7 @@ import at.connyduck.pixelcat.databinding.ActivityMainBinding
import at.connyduck.pixelcat.db.AccountManager import at.connyduck.pixelcat.db.AccountManager
import com.fxn.pix.Options import com.fxn.pix.Options
import com.fxn.pix.Pix import com.fxn.pix.Pix
import com.fxn.utility.ImageQuality import com.google.android.material.navigation.NavigationBarView
import com.google.android.material.bottomnavigation.BottomNavigationView
import javax.inject.Inject import javax.inject.Inject
class MainActivity : BaseActivity() { class MainActivity : BaseActivity() {
@ -54,8 +53,8 @@ class MainActivity : BaseActivity() {
private lateinit var mainFragmentAdapter: MainFragmentAdapter private lateinit var mainFragmentAdapter: MainFragmentAdapter
private val onNavigationItemSelectedListener = private val onNavigationItemSelectedListener =
BottomNavigationView.OnNavigationItemSelectedListener { item -> NavigationBarView.OnItemSelectedListener { item ->
return@OnNavigationItemSelectedListener when (item.itemId) { return@OnItemSelectedListener when (item.itemId) {
R.id.navigation_home -> { R.id.navigation_home -> {
binding.mainViewPager.setCurrentItem(0, false) binding.mainViewPager.setCurrentItem(0, false)
true true
@ -67,7 +66,6 @@ class MainActivity : BaseActivity() {
R.id.navigation_compose -> { R.id.navigation_compose -> {
val options = Options.init() val options = Options.init()
.setRequestCode(100) .setRequestCode(100)
.setImageQuality(ImageQuality.HIGH)
.setScreenOrientation(Options.SCREEN_ORIENTATION_PORTRAIT) .setScreenOrientation(Options.SCREEN_ORIENTATION_PORTRAIT)
Pix.start(this, options) Pix.start(this, options)
@ -102,7 +100,7 @@ class MainActivity : BaseActivity() {
binding.mainViewPager.adapter = mainFragmentAdapter binding.mainViewPager.adapter = mainFragmentAdapter
binding.mainViewPager.isUserInputEnabled = false binding.mainViewPager.isUserInputEnabled = false
binding.navigation.setOnNavigationItemSelectedListener(onNavigationItemSelectedListener) binding.navigation.setOnItemSelectedListener(onNavigationItemSelectedListener)
mainViewModel.whatever() mainViewModel.whatever()
} }

View File

@ -23,7 +23,6 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadState import androidx.paging.LoadState
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
@ -52,7 +51,6 @@ class NotificationsFragment :
private val binding by viewBinding(FragmentNotificationsBinding::bind) private val binding by viewBinding(FragmentNotificationsBinding::bind)
@ExperimentalPagingApi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.notificationSwipeRefresh.setColorSchemeColors( binding.notificationSwipeRefresh.setColorSchemeColors(

View File

@ -33,14 +33,13 @@ import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.flatMapConcat import kotlinx.coroutines.flow.flatMapConcat
import javax.inject.Inject import javax.inject.Inject
@OptIn(ExperimentalPagingApi::class, FlowPreview::class)
class NotificationsViewModel @Inject constructor( class NotificationsViewModel @Inject constructor(
accountManager: AccountManager, accountManager: AccountManager,
private val db: AppDatabase, private val db: AppDatabase,
private val api: FediverseApi private val api: FediverseApi
) : ViewModel() { ) : ViewModel() {
@OptIn(FlowPreview::class)
@ExperimentalPagingApi
val notificationsFlow = accountManager::activeAccount.asFlow() val notificationsFlow = accountManager::activeAccount.asFlow()
.flatMapConcat { activeAccount -> .flatMapConcat { activeAccount ->
Pager( Pager(

View File

@ -23,13 +23,13 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.paging.ExperimentalPagingApi
import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import at.connyduck.pixelcat.R import at.connyduck.pixelcat.R
import at.connyduck.pixelcat.components.bottomsheet.accountselection.AccountSelectionBottomSheet import at.connyduck.pixelcat.components.bottomsheet.accountselection.AccountSelectionBottomSheet
import at.connyduck.pixelcat.components.bottomsheet.menu.MenuBottomSheet import at.connyduck.pixelcat.components.bottomsheet.menu.MenuBottomSheet
import at.connyduck.pixelcat.components.main.MainActivity import at.connyduck.pixelcat.components.main.MainActivity
import at.connyduck.pixelcat.components.util.Error
import at.connyduck.pixelcat.components.util.Success import at.connyduck.pixelcat.components.util.Success
import at.connyduck.pixelcat.components.util.extension.getDisplayWidthInPx import at.connyduck.pixelcat.components.util.extension.getDisplayWidthInPx
import at.connyduck.pixelcat.dagger.ViewModelFactory import at.connyduck.pixelcat.dagger.ViewModelFactory
@ -63,7 +63,6 @@ class ProfileFragment : DaggerFragment(R.layout.fragment_profile) {
private val headerAdapter = ProfileHeaderAdapter() private val headerAdapter = ProfileHeaderAdapter()
private lateinit var imageAdapter: ProfileImageAdapter private lateinit var imageAdapter: ProfileImageAdapter
@ExperimentalPagingApi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (activity is MainActivity) { if (activity is MainActivity) {
@ -111,23 +110,22 @@ class ProfileFragment : DaggerFragment(R.layout.fragment_profile) {
viewModel.setAccountInfo(arg(ACCOUNT_ID)) viewModel.setAccountInfo(arg(ACCOUNT_ID))
viewModel.profile.observe( viewModel.profile.observe(
viewLifecycleOwner, viewLifecycleOwner
{ ) {
when (it) { when (it) {
is Success -> onAccountChanged(it.data) is Success -> onAccountChanged(it.data)
is Error -> showError() is Error -> showError()
} else -> {}
} }
) }
viewModel.relationship.observe( viewModel.relationship.observe(
viewLifecycleOwner, viewLifecycleOwner
{ ) {
when (it) { when (it) {
is Success -> onRelationshipChanged(it.data) is Success -> onRelationshipChanged(it.data)
is Error -> showError() is Error -> showError()
}
} }
) }
lifecycleScope.launch { lifecycleScope.launch {
viewModel.imageFlow.collectLatest { imageAdapter.submitData(it) } viewModel.imageFlow.collectLatest { imageAdapter.submitData(it) }
} }

View File

@ -20,6 +20,7 @@
package at.connyduck.pixelcat.components.profile package at.connyduck.pixelcat.components.profile
import androidx.paging.PagingSource import androidx.paging.PagingSource
import androidx.paging.PagingState
import at.connyduck.pixelcat.db.AccountManager import at.connyduck.pixelcat.db.AccountManager
import at.connyduck.pixelcat.model.Status import at.connyduck.pixelcat.model.Status
import at.connyduck.pixelcat.network.FediverseApi import at.connyduck.pixelcat.network.FediverseApi
@ -54,4 +55,6 @@ class ProfileImagePagingSource(
} }
) )
} }
override fun getRefreshKey(state: PagingState<String, Status>): String? = null
} }

View File

@ -37,6 +37,7 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@OptIn(FlowPreview::class, ExperimentalPagingApi::class)
class ProfileViewModel @Inject constructor( class ProfileViewModel @Inject constructor(
private val api: FediverseApi, private val api: FediverseApi,
private val accountManager: AccountManager private val accountManager: AccountManager
@ -45,8 +46,6 @@ class ProfileViewModel @Inject constructor(
val profile = MutableLiveData<UiState<Account>>() val profile = MutableLiveData<UiState<Account>>()
val relationship = MutableLiveData<UiState<Relationship>>() val relationship = MutableLiveData<UiState<Relationship>>()
@OptIn(FlowPreview::class)
@ExperimentalPagingApi
val imageFlow = Pager( val imageFlow = Pager(
config = PagingConfig(pageSize = 10, enablePlaceholders = false), config = PagingConfig(pageSize = 10, enablePlaceholders = false),
pagingSourceFactory = { ProfileImagePagingSource(api, accountId, accountManager) } pagingSourceFactory = { ProfileImagePagingSource(api, accountId, accountManager) }

View File

@ -23,7 +23,6 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadState import androidx.paging.LoadState
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
@ -49,7 +48,6 @@ class TimelineFragment : DaggerFragment(R.layout.fragment_timeline), TimeLineAct
private val binding by viewBinding(FragmentTimelineBinding::bind) private val binding by viewBinding(FragmentTimelineBinding::bind)
@ExperimentalPagingApi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.timelineSwipeRefresh.setColorSchemeColors( binding.timelineSwipeRefresh.setColorSchemeColors(

View File

@ -35,6 +35,7 @@ import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@OptIn(FlowPreview::class, ExperimentalPagingApi::class)
class TimelineViewModel @Inject constructor( class TimelineViewModel @Inject constructor(
accountManager: AccountManager, accountManager: AccountManager,
private val db: AppDatabase, private val db: AppDatabase,
@ -42,8 +43,6 @@ class TimelineViewModel @Inject constructor(
private val useCases: TimelineUseCases private val useCases: TimelineUseCases
) : ViewModel() { ) : ViewModel() {
@OptIn(FlowPreview::class)
@ExperimentalPagingApi
val statusFlow = accountManager::activeAccount.asFlow() val statusFlow = accountManager::activeAccount.asFlow()
.flatMapConcat { activeAccount -> .flatMapConcat { activeAccount ->
Pager( Pager(

View File

@ -76,46 +76,44 @@ class DetailActivity : BaseActivity(), TimeLineActionListener {
binding.detailRecyclerView.adapter = ConcatAdapter(statusAdapter, repliesAdapter) binding.detailRecyclerView.adapter = ConcatAdapter(statusAdapter, repliesAdapter)
viewModel.currentStatus.observe( viewModel.currentStatus.observe(
this, this
{ ) {
when (it) { when (it) {
is Success -> { is Success -> {
binding.detailSwipeRefresh.show() binding.detailSwipeRefresh.show()
binding.detailStatus.hide() binding.detailStatus.hide()
binding.detailProgress.hide() binding.detailProgress.hide()
binding.detailSwipeRefresh.isRefreshing = false binding.detailSwipeRefresh.isRefreshing = false
binding.detailRecyclerView.show() binding.detailRecyclerView.show()
statusAdapter.submitList(listOf(it.data)) statusAdapter.submitList(listOf(it.data))
it.data?.let { status -> it.data?.let { status ->
if (intent.getBooleanExtra(EXTRA_REPLY, false)) { if (intent.getBooleanExtra(EXTRA_REPLY, false)) {
intent.removeExtra(EXTRA_REPLY) intent.removeExtra(EXTRA_REPLY)
onReply(status) onReply(status)
}
} }
} }
is Loading -> { }
binding.detailSwipeRefresh.hide() is Loading -> {
binding.detailStatus.hide() binding.detailSwipeRefresh.hide()
binding.detailProgress.show() binding.detailStatus.hide()
} binding.detailProgress.show()
is Error -> { }
binding.detailSwipeRefresh.hide() is Error -> {
binding.detailStatus.show() binding.detailSwipeRefresh.hide()
binding.detailProgress.hide() binding.detailStatus.show()
binding.detailStatus.showGeneralError() binding.detailProgress.hide()
} binding.detailStatus.showGeneralError()
} }
} }
) }
viewModel.replies.observe( viewModel.replies.observe(
this, this
{ ) {
if (it is Success) { if (it is Success) {
repliesAdapter.submitList(it.data) repliesAdapter.submitList(it.data)
}
} }
) }
} }
override fun onFavorite(status: StatusEntity) { override fun onFavorite(status: StatusEntity) {

View File

@ -132,7 +132,7 @@ class DetailViewModel @Inject constructor(
NewStatus( NewStatus(
status = replyText, status = replyText,
inReplyToId = statusToReply.actionableId, inReplyToId = statusToReply.actionableId,
visibility = statusToReply.visibility.name.toLowerCase(Locale.ROOT), visibility = statusToReply.visibility.name.lowercase(Locale.ROOT),
sensitive = statusToReply.sensitive, sensitive = statusToReply.sensitive,
mediaIds = null mediaIds = null
) )

View File

@ -27,6 +27,6 @@ import java.util.Locale
* @return the mime type, or null if it couldn't be determined * @return the mime type, or null if it couldn't be determined
*/ */
fun getMimeType(filePath: String): String? { fun getMimeType(filePath: String): String? {
val extension = filePath.split('.').lastOrNull()?.toLowerCase(Locale.ROOT) ?: return null val extension = filePath.split('.').lastOrNull()?.lowercase(Locale.ROOT) ?: return null
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
} }

View File

@ -46,9 +46,9 @@ data class Account(
) { ) {
val name: String val name: String
get() = if (displayName.isEmpty()) { get() = displayName.ifEmpty {
localUsername localUsername
} else displayName }
} }
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)

View File

@ -32,17 +32,16 @@ class FragmentViewBindingDelegate<T : ViewBinding>(
object : DefaultLifecycleObserver { object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) { override fun onCreate(owner: LifecycleOwner) {
fragment.viewLifecycleOwnerLiveData.observe( fragment.viewLifecycleOwnerLiveData.observe(
fragment, fragment
{ t -> ) { t ->
t?.lifecycle?.addObserver( t?.lifecycle?.addObserver(
object : DefaultLifecycleObserver { object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) { override fun onDestroy(owner: LifecycleOwner) {
binding = null binding = null
}
} }
) }
} )
) }
} }
} }
) )

View File

@ -5,9 +5,9 @@ buildscript {
gradlePluginPortal() gradlePluginPortal()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:4.1.0") classpath("com.android.tools.build:gradle:7.1.0")
classpath(kotlin("gradle-plugin", version = "1.4.10")) classpath(kotlin("gradle-plugin", version = "1.6.10"))
classpath("org.jlleitschuh.gradle:ktlint-gradle:9.4.0") classpath("org.jlleitschuh.gradle:ktlint-gradle:10.2.1")
} }
} }

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

2
gradlew vendored
View File

@ -72,7 +72,7 @@ case "`uname`" in
Darwin* ) Darwin* )
darwin=true darwin=true
;; ;;
MINGW* ) MSYS* | MINGW* )
msys=true msys=true
;; ;;
NONSTOP* ) NONSTOP* )