### Jetpack Compose UI Implementation
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Example of Jetpack Compose usage for building the UI, adhering to Material 3 design principles and supporting different screen sizes.
```kotlin
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
```
--------------------------------
### Build Variants and Product Flavors
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Description of the build variants (debug, release) and product flavors (demo, prod) used in the application. The 'demo' flavor is intended for immediate exploration, while 'prod' fetches live data. Currently, both flavors connect to the backend.
```gradle
android {
// ...
buildTypes {
release {
// ...
}
debug {
// ...
}
}
flavorDimensions "default"
productFlavors {
create("demo") {
dimension "default"
// ...
}
create("prod") {
dimension "default"
// ...
}
}
}
```
--------------------------------
### License Information
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Displays the project's license, which is Apache License 2.0, and provides a link to the license file.
```markdown
## License
[](https://github.com/azrael8576/vsclock/blob/main/LICENSE)
**VsClock** is distributed under the terms of the Apache License (Version 2.0). See the [license](https://github.com/azrael8576/vsclock/blob/main/LICENSE) for more information.
```
--------------------------------
### Retrofit and OkHttp for Network Requests
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Configuration for Retrofit and OkHttp libraries used for constructing REST APIs and paging network data.
```kotlin
import retrofit2.Retrofit
import okhttp3.OkHttpClient
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(OkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.build()
interface ApiService {
// Define API methods here
}
```
--------------------------------
### VsClock Testing Strategies
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Details the testing methodologies employed in the VsClock project, including Test double with Hilt, Robot Testing Pattern for UI interactions, and Screenshot tests using Roborazzi.
```markdown
## Testing
本專案主要採用 **Test double**、**Robot Testing Pattern** 以及 **Screenshot tests** 作為測試策略,使測試更加健全且易於維護。
### 1. Test double
在 **VsClock** 專案中,我們使用了 [_Hilt_](https://developer.android.com/training/dependency-injection/hilt-android?hl=en) 來進行依賴注入。而在資料層,我們將元件定義成接口形式,並依照具體需求進行實現綁定。
#### 策略亮點:
- **VsClock** 並**未使用**任何 mocking libraries,而選擇使用 Hilt 的測試 API,方便我們將正式版本輕鬆替換成測試版本。
- 測試版本與正式版本保持相同的接口,但是測試版本的實現更為簡單且真實,且有特定的測試掛鉤。
- 這種設計策略不僅降低了測試的脆弱性,還有效提高了代碼覆蓋率。
#### 實例:
- 在測試過程中,我們為每個 repository 提供測試版本。在測試 `ViewModel` 時,這些測試版的 repository 會被使用,進而透過測試掛鉤操控其狀態並確認測試結果。
### 2. Robot Testing Pattern
對於 UI Testing,**VsClock** 採用了 [_Robot Testing Pattern_](https://jakewharton.com/testing-robots/?source=post_page-----fc820ce250f7--------------------------------),其核心目的是建立一個抽象層,以聲明性的方式進行 UI 交互。
#### 策略特點:
1. **易於理解**:測試內容直觀,使用者可以快速理解而不必深入了解其背後的實現。
2. **代碼重用**:通過將測試進行模組化,能夠重複使用測試步驟,從而提高測試效率。
3. **隔離實現細節**:透過策略分層,確保了代碼遵循單一責任原則,這不僅提高了代碼的維護性,還使得測試和優化過程更為簡便。
### 3. Screenshot tests
**VsClock** 使用 [_Roborazzi_](https://github.com/takahirom/roborazzi) 進行特定畫面和組件的截圖測試。要運行這些測試,請執行 `verifyRoborazziDemoDebug` 或 `recordRoborazziDemoDebug` 任務。
> [!IMPORTANT]
> 截圖是在 CI 上使用 Linux 記錄的,其他平台可能產生略有不同的圖像,使得測試失敗。
```
--------------------------------
### VsClock Module Overview
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Provides a summary of the different module types within the VsClock project, including their responsibilities and key classes. This helps in understanding the project's architecture and how different components interact.
```markdown
## Types of modules in VsClock

**Top tip**:模組圖(如上所示)在模組化規劃期間有助於視覺化展示模組間的依賴性。
VsClock 主要包含以下幾種模組:
- `app` 模組 - 此模組包含 app 級別的核心組件和 scaffolding 類,例如 `MainActivity`、`VsclockApp` 以及 app 級別控制的導航。`app` 模組將會依賴所有的 `feature` 模組和必要的 `core` 模組。
- `feature:` 模組 - 這些模組各自專注於某個特定功能或用戶的互動流程。每個模組都只聚焦於一個特定的功能職責。如果某個類別只被一個 `feature` 模組所需要,那麼它應只存在於該模組中;若非如此,則應該將其移至適當的 `core` 模組。每個 `feature` 模組應避免依賴其他 `feature` 模組,並只應依賴其所需的 `core` 模組。
- `core:` 模組 - 這些模組是公共的函式庫模組,它們包含了眾多輔助功能的程式碼和那些需要在多個模組間共享的依賴項。這些模組可以依賴其他 `core` 模組,但絕不應依賴於`feature`模組或`app`模組。
- 其他各種模組:例如 `test` 模組,主要用於進行軟體測試。
## Modules
採用上述模組化策略,VsClock 應用程序具有以下模組:
| Name | Responsibilities | Key classes and good examples |
|:----:|:----:|:-----------------:|
| `app` | 將所有必要元素整合在一起,確保應用程式的正確運作。
eg. UI scaffolding、navigation...等 | `VsclockApplication,`
`VsclockNavHost`
`TopLevelDestination`
`VsclockApp`
`VsclockAppState` |
| `feature:1`,
`feature:2`
... | 負責實現某個特定功能或用戶的互動流程的部分。這通常包含 UI 組件、UseCase 和 ViewModel,並從其他模組讀取資料。例如:
• [`feature:times`](https://github.com/azrael8576/vsclock/tree/main/feature/times) 專注於展示數位時鐘。
• [`feature:setting`](https://github.com/azrael8576/vsclock/tree/main/feature/setting) 提供數位時鐘的 CRUD介面 | `TimesScreen,`
`TimesViewModel,`
`service/FloatingTimeService`
... |
| `core:data` | 負責從多個來源獲取應用程式的資料,並供其他功能模組共享。 | `TimeRepository,`
`RefreshStateRepository,`
`utils/ConnectivityManagerNetworkMonitor`|
| `core:common` | 包含被多個模組共享的通用類別。
eg. 工具類、擴展方法...等 | `network/VsclockDispatchers,`
`result/DataSourceResult,`
`extensions/StateFlowStateExtensions,`
`utils/UiText`
... |
| `core:domain` | 包含被多個模組共享的 UseCase。 | None |
| `core:model` | 提供整個應用程式所使用的模型類別。 | `CurrentTime` |
| `core:network` | 負責發送網絡請求,並處理來自遠程數據源的回應。 | `RetrofitVsclockNetwork` |
| `core:designsystem` | UI 依賴項。
eg. app theme、Core UI 元件樣式...等 | `VsclockTheme,`
`component/VsclockAppSnackbar`
... |
| `core:testing` | 測試依賴項、repositories 和 util 類。 | `MainDispatcherRule,`
`VsclockTestRunner,`
... |
| `core:database` | 儲存持久性數據 | `VsclockDatabase,`
`dao/CurrentTimeDao,`
... |
```
--------------------------------
### Testing Libraries
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Overview of testing libraries used, including Turbine for Flows, Google Truth for assertions, Roborazzi for screenshot testing, and Robolectric for unit testing.
```kotlin
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import org.junit.Test
// Example using Turbine
@Test
fun testFlow() {
val flow = flowOf(1, 2, 3)
runBlocking {
flow.test {
assertThat(awaitItem()).isEqualTo(1)
assertThat(awaitItem()).isEqualTo(2)
assertThat(awaitItem()).isEqualTo(3)
awaitComplete()
}
}
}
```
--------------------------------
### Coil for Image Loading
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Usage of Coil, an image loading library for Android, backed by Kotlin Coroutines.
```kotlin
import coil.compose.AsyncImage
import androidx.compose.runtime.Composable
@Composable
fun MyImageLoader(url: String) {
AsyncImage(
model = url,
contentDescription = "Image description"
)
}
```
--------------------------------
### Room Database for Data Persistence
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Implementation details for Room, an SQLite persistence library for Android, ensuring the Single Source of Truth (SSOT) principle.
```kotlin
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(entities = [YourEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun yourDao(): YourDao
}
```
--------------------------------
### MVI Architecture Components
Source: https://github.com/azrael8576/vsclock/blob/main/README.md
Encapsulations for common MVI patterns in Android development, including a BaseViewModel, StateFlow extensions, and data source result handling with retry mechanisms.
```kotlin
class BaseViewModel : ViewModel() {
protected val _state = MutableStateFlow(initialState())
val state: StateFlow = _state.asStateFlow()
abstract fun initialState(): State
abstract fun dispatch(intent: Intent)
}
sealed class DataSourceResult {
data class Success(val data: T) : DataSourceResult()
data class Error(val exception: Throwable) : DataSourceResult()
data object Loading : DataSourceResult()
}
fun Flow.asDataSourceResultWithRetry(traceTag: String, maxRetries: Int = 3):
Flow> = retryWhen {
cause, attempt ->
if (attempt < maxRetries) {
Log.w(traceTag, "Retry attempt $attempt of $maxRetries")
emit(DataSourceResult.Error(cause as Exception))
delay((1000 * attempt).toLong())
} else {
emit(DataSourceResult.Error(cause as Exception))
throw cause
}
}.map {
DataSourceResult.Success(it) as DataSourceResult
}.onStart {
emit(DataSourceResult.Loading)
}
```
--------------------------------
### Android Application Convention Plugin
Source: https://github.com/azrael8576/vsclock/blob/main/build-logic/README.md
Configures common Android and Kotlin options for application modules. This plugin centralizes build logic for Android applications.
```kotlin
package vsclock.android.application
import org.gradle.api.Plugin
import org.gradle.api.Project
class AndroidApplicationConventionPlugin : Plugin {
override fun apply(target: Project) {
with(target) {
// Common Android and Kotlin configurations for applications
}
}
}
```
--------------------------------
### Android Library Convention Plugin
Source: https://github.com/azrael8576/vsclock/blob/main/build-logic/README.md
Configures common Android and Kotlin options for library modules. This plugin centralizes build logic for Android libraries.
```kotlin
package vsclock.android.library
import org.gradle.api.Plugin
import org.gradle.api.Project
class AndroidLibraryConventionPlugin : Plugin {
override fun apply(target: Project) {
with(target) {
// Common Android and Kotlin configurations for libraries
}
}
}
```
--------------------------------
### Android Test Convention Plugin
Source: https://github.com/azrael8576/vsclock/blob/main/build-logic/README.md
Configures common Android and Kotlin options for test modules. This plugin centralizes build logic for Android test configurations.
```kotlin
package vsclock.android.test
import org.gradle.api.Plugin
import org.gradle.api.Project
class AndroidTestConventionPlugin : Plugin {
override fun apply(target: Project) {
with(target) {
// Common Android and Kotlin configurations for tests
}
}
}
```
--------------------------------
### Android Library Compose Convention Plugin
Source: https://github.com/azrael8576/vsclock/blob/main/build-logic/README.md
Configures Jetpack Compose options for Android library modules. This plugin enables and configures Compose for libraries.
```kotlin
package vsclock.android.library.compose
import org.gradle.api.Plugin
import org.gradle.api.Project
class AndroidLibraryComposeConventionPlugin : Plugin {
override fun apply(target: Project) {
with(target) {
// Jetpack Compose configurations for libraries
}
}
}
```
--------------------------------
### Android Application Compose Convention Plugin
Source: https://github.com/azrael8576/vsclock/blob/main/build-logic/README.md
Configures Jetpack Compose options for Android application modules. This plugin enables and configures Compose for applications.
```kotlin
package vsclock.android.application.compose
import org.gradle.api.Plugin
import org.gradle.api.Project
class AndroidApplicationComposeConventionPlugin : Plugin {
override fun apply(target: Project) {
with(target) {
// Jetpack Compose configurations for applications
}
}
}
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.