Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SwiftUI and some compose refactors #201

Merged
merged 22 commits into from Aug 5, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 12 additions & 17 deletions .github/pull_request_template.md
Expand Up @@ -3,25 +3,20 @@
<!-- Add issue link -->
Issue: https://github.com/touchlab/KaMPKit/issues/[issue number]

## [Platform]
<!-- Select / Unselect the appropriate platforms -->
- [x] iOS
- [ ] Android
- [x] KMP

## [Summary]
## Summary
<!--- Copy summary from issue link or write a shortened description of it -->

## [Fix]
## Fix
<!-- What did you do to fix the issue? -->

## [Testing]
- <!-- (if applicable) unit tests -->
- <!-- (if applicable) integration tests -->
- <!-- (if applicable) UI tests -->
- <!-- (if applicable) manual tests -->
- <!-- (if applicable) screenshots -->
## Testing
<!-- Remove any lines that were not performed -->
- `./gradlew :app:build`
- `./gradlew :shared:build`
- `xcodebuild -workspace ios/KaMPKitiOS.xcworkspace -scheme KaMPKitiOS
-sdk iphoneos -configuration Debug build -destination name="iPhone 8"`
- manual testing

###### Reviewer Tips:
###### * Use "Nitpick:" if it's a minor non-crucial request.
###### * If you're done with comments either end with a review or comment something helpful like "done with comments for now"
<!-- If you made changes to the UI, please show us what it looks like now. -->
### **Screenshot / Video of App working with the Changes**
<img width="250" alt="fix in action" src="https://media.makeameme.org/created/yes-it-works.jpg">
5 changes: 5 additions & 0 deletions .github/workflows/KaMPKit-Android.yml
Expand Up @@ -19,6 +19,11 @@ jobs:
steps:
- uses: actions/checkout@v2

- uses: actions/setup-java@v2
with:
distribution: "adopt"
java-version: "11"

- name: Build
run: ./gradlew :app:build

Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/KaMPKit-Shared.yml
Expand Up @@ -20,6 +20,11 @@ jobs:
steps:
- uses: actions/checkout@v2

- uses: actions/setup-java@v2
with:
distribution: "adopt"
java-version: "11"

- name: Build
run: ./gradlew :shared:build

Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/KaMPKit-iOS.yml
Expand Up @@ -19,6 +19,11 @@ jobs:
steps:
- uses: actions/checkout@v2

- uses: actions/setup-java@v2
with:
distribution: "adopt"
java-version: "11"

- name: Build
uses: sersoft-gmbh/xcodebuild-action@v1
with:
Expand Down
9 changes: 0 additions & 9 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions README.md
@@ -1,7 +1,5 @@
[![KaMPKit Shared](https://img.shields.io/github/workflow/status/touchlab/KaMPKit/KaMPKit-Shared?logo=kotlin&style=plastic)](https://github.com/touchlab/KaMPKit/actions/workflows/KaMPKit-Shared.yml)
[![KaMPKit Android](https://img.shields.io/github/workflow/status/touchlab/KaMPKit/KaMPKit-Android/main?logo=Android&style=plastic)](https://github.com/touchlab/KaMPKit/actions/workflows/KaMPKit-Android.yml)
[![KaMPKit iOS](https://img.shields.io/github/workflow/status/touchlab/KaMPKit/KaMPKit-iOS?logo=iOS&style=plastic)](https://github.com/touchlab/KaMPKit/actions/workflows/KaMPKit-iOS.yml)

[![KaMPKit Android](https://img.shields.io/github/workflow/status/touchlab/KaMPKit/KaMPKit-Android/main?logo=Android&style=plastic)](https://github.com/touchlab/KaMPKit/actions/workflows/KaMPKit-Android.yml)
[![KaMPKit iOS](https://img.shields.io/github/workflow/status/touchlab/KaMPKit/KaMPKit-iOS?logo=iOS&style=plastic)](https://github.com/touchlab/KaMPKit/actions/workflows/KaMPKit-iOS.yml)

# KaMP Kit

Expand Down
31 changes: 19 additions & 12 deletions app/build.gradle.kts
Expand Up @@ -4,18 +4,18 @@ plugins {
}

android {
compileSdkVersion(Versions.compile_sdk)
compileSdk = Versions.compile_sdk
buildToolsVersion = Versions.buildToolsVersion
defaultConfig {
applicationId = "co.touchlab.kampkit"
minSdkVersion(Versions.min_sdk)
targetSdkVersion(Versions.target_sdk)
minSdk = Versions.min_sdk
targetSdk = Versions.target_sdk
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
packagingOptions {
exclude("META-INF/*.kotlin_module")
resources.excludes.add("META-INF/*.kotlin_module")
}
buildTypes {
getByName("release") {
Expand All @@ -29,31 +29,31 @@ android {
targetCompatibility = JavaVersion.VERSION_1_8
}

lintOptions {
lint {
isWarningsAsErrors = true
isAbortOnError = true
}

buildFeatures {
viewBinding = true
compose = true
}

kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn"
}

composeOptions {
kotlinCompilerExtensionVersion = Versions.Compose.compose
}
}

dependencies {
implementation(project(":shared"))
implementation(Deps.AndroidX.recyclerView)
implementation(Deps.AndroidX.swipeRefresh)
implementation(Deps.material)
coreLibraryDesugaring(Deps.desugarJdkLibs)
implementation(Deps.AndroidX.appcompat)
implementation(Deps.AndroidX.core_ktx)
implementation(Deps.Ktor.androidCore)
implementation(Deps.AndroidX.constraintlayout)
implementation(Deps.SqlDelight.runtimeJdk)
implementation(Deps.SqlDelight.driverAndroid)
implementation(Deps.Coroutines.common)
Expand All @@ -64,6 +64,13 @@ dependencies {
implementation(Deps.AndroidX.lifecycle_runtime)
implementation(Deps.AndroidX.lifecycle_viewmodel)
implementation(Deps.AndroidX.lifecycle_viewmodel_extensions)
implementation(Deps.AndroidX.lifecycle_livedata)

implementation(Deps.Compose.activityCompose)
implementation(Deps.Compose.ui)
implementation(Deps.Compose.uiTooling)
implementation(Deps.Compose.foundation)
implementation(Deps.Compose.material)
implementation(Deps.Compose.Accompanist.swipeRefresh)

testImplementation(Deps.junit)
}
7 changes: 4 additions & 3 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -10,9 +10,10 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:name="co.touchlab.kampkit.android.MainApp"
>
<activity android:name="co.touchlab.kampkit.android.MainActivity">
android:name="co.touchlab.kampkit.android.MainApp">
<activity
android:name="co.touchlab.kampkit.android.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand Down
18 changes: 14 additions & 4 deletions app/src/main/java/co/touchlab/kampkit/android/BreedViewModel.kt
Expand Up @@ -24,7 +24,7 @@ class BreedViewModel : ViewModel(), KoinComponent {
private val scope = viewModelScope
private val breedModel: BreedModel = BreedModel()
private val _breedStateFlow: MutableStateFlow<DataState<ItemDataSummary>> = MutableStateFlow(
DataState.Loading
DataState(loading = true)
)

val breedStateFlow: StateFlow<DataState<ItemDataSummary>> = _breedStateFlow
Expand All @@ -41,16 +41,26 @@ class BreedViewModel : ViewModel(), KoinComponent {
breedModel.refreshBreedsIfStale(true),
breedModel.getBreedsFromCache()
).flattenMerge().collect { dataState ->
_breedStateFlow.value = dataState
if (dataState.loading) {
val temp = _breedStateFlow.value.copy(loading = true)
_breedStateFlow.value = temp
} else {
_breedStateFlow.value = dataState
}
}
}
}

fun refreshBreeds(forced: Boolean = false) {
scope.launch {
log.v { "refreshBreeds" }
breedModel.refreshBreedsIfStale(forced).collect {
_breedStateFlow.value = it
breedModel.refreshBreedsIfStale(forced).collect { dataState ->
if (dataState.loading) {
val temp = _breedStateFlow.value.copy(loading = true)
_breedStateFlow.value = temp
} else {
_breedStateFlow.value = dataState
}
}
}
}
Expand Down
93 changes: 11 additions & 82 deletions app/src/main/java/co/touchlab/kampkit/android/MainActivity.kt
@@ -1,101 +1,30 @@
package co.touchlab.kampkit.android

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import co.touchlab.kampkit.android.adapter.MainAdapter
import co.touchlab.kampkit.android.databinding.ActivityMainBinding
import co.touchlab.kampkit.db.Breed
import co.touchlab.kampkit.models.DataState
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import co.touchlab.kampkit.android.ui.MainScreen
import co.touchlab.kampkit.android.ui.theme.KaMPKitTheme
import co.touchlab.kermit.Kermit
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.parameter.parametersOf

class MainActivity : AppCompatActivity(), KoinComponent {
class MainActivity : ComponentActivity(), KoinComponent {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppCompatActivity is a ComponentActivity; why the change?


private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
private val log: Kermit by inject { parametersOf("MainActivity") }
private val viewModel: BreedViewModel by viewModel()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)

val adapter = MainAdapter { viewModel.updateBreedFavorite(it) }
val swipeRefresh: SwipeRefreshLayout = binding.swipeRefresh
val recyclerView: RecyclerView = binding.breedList

swipeRefresh.setOnRefreshListener {
viewModel.refreshBreeds(true)
}

collectDataStateFlow(
{
/* Display loading view */
swipeRefresh.isRefreshing = true
},
{ breedList ->
/* Display success view */
swipeRefresh.isRefreshing = false
recyclerView.visibility = View.VISIBLE
log.v { "View updating with ${breedList.size} breeds" }
adapter.submitList(breedList)
},
{ exception ->
/* Display error view */
swipeRefresh.isRefreshing = false
recyclerView.visibility = View.GONE
log.e { "Displaying error: $exception" }
Snackbar.make(
binding.breedList,
exception,
Snackbar.LENGTH_SHORT
).show()
},
{
/* Display empty response view */
swipeRefresh.isRefreshing = false
}
)

binding.breedList.adapter = adapter
binding.breedList.layoutManager = LinearLayoutManager(this)

viewModel.refreshBreeds()
}

private fun collectDataStateFlow(
onLoading: () -> Unit,
onSuccess: (List<Breed>) -> Unit,
onError: (String) -> Unit,
onEmpty: () -> Unit,
) {
lifecycleScope.launch {
viewModel.breedStateFlow.collect { dataState ->
when (dataState) {
is DataState.Success -> {
onSuccess(dataState.data.allItems)
}
is DataState.Error -> {
onError(dataState.exception)
}
DataState.Empty -> {
onEmpty()
}
DataState.Loading -> {
onLoading()
}
}
setContent {
KaMPKitTheme {
MainScreen(viewModel, log)
}
}
if (viewModel.breedStateFlow.value.data == null) {
viewModel.refreshBreeds()
}
}
}

This file was deleted.