Conversation
Replaces the legacy Java/XML sample app (MainActivity.java, SampleApplication.java, activity_main.xml, PNG launcher icons, w820dp resources) with a modern Kotlin and Jetpack Compose implementation that demonstrates the SumUp Reader SDK using a layered, testable architecture. Architecture - Introduces a Clean Architecture structure with domain/, data/ and `presentation/` layers, each holding only framework-appropriate types. - Domain: `ReaderSdkRepository` interface, pure Kotlin models (`MerchantInfo`, `ConnectedReader`, `ReaderType`, `OfflineSession`, `OfflineSdkError`, `SdkResult`, `CheckoutConfiguration`) and four `suspend`-enabled use cases (`CreateLoginRequestUseCase`, `CreateCheckoutRequestUseCase`, `ParseSdkStatusUseCase`, `ParsePaymentResultUseCase`), all returning `Result<T>` via `runCatching`. - Data: `ReaderSdkRepositoryImpl` wraps the SumUp SDK callbacks as coroutines and delegates conversion to dedicated mappers (`MerchantInfoMapper`, `ConnectedReaderMapper`, `OfflineSessionMapper`). - Presentation: a single `MainViewModel` exposing `StateFlow<UiState>` + `Channel<UiEvent>` drives three Compose screens — `WelcomeScreen`, `CheckoutScreen`, `SettingsScreen` — composed from `AmountDisplay`, `Keypad` and `CheckoutResultDialog`. `SdkActionRequest` lives in the presentation layer so SumUp SDK types never leak into domain. - Navigation uses `NavHost` with type-safe routes (`Welcome`, `Checkout`, `Settings`) hosted inside a `Scaffold` whose padding is propagated down. - Koin wires the whole graph in `di/KoinModules.kt`; a coroutine dispatcher abstraction (`CoroutinesDispatcherProvider` + `DefaultCoroutinesDispatcherProvider`) keeps the ViewModel testable. UI / UX - Edge-to-edge rendering via `enableEdgeToEdge()`; screens apply `statusBarsPadding()` and `navigationBarsPadding()` and manage system bar icon tint with a `SystemBarsAppearance` helper. - New design system in `theme/` (`SparkBlue`, `Violet`, `LightSand`, …) and typography scale (`AmountTextStyle`, `ButtonLabelStyle`, …) plugged into `MaterialTheme`'s `Typography` slot for consistent Material3 defaults. - Checkout screen features an auto-sizing amount display, custom keypad, reader-status badge, offline indicator and a Material3 `Button` whose `enabled` state is bound to `isLoggedIn && amountInCents > 0`. - Settings screen surfaces tipping configuration (on-reader vs manual), offline-session controls (start/stop, upload transactions, security patch update), developer toggles (result dialog, success screen + custom timeout) and account/logout actions, with preview fixtures for each state. - New launcher icon (adaptive `ic_launcher` + foreground/background vectors), `ic_settings_gear`, `ic_close`, `ic_location_pin`, `ic_sumup_logo`, and a `bg_welcome_map` welcome background. Error handling & observability - `SafeResult.safely`/`safelySuspend` wrap SDK calls, log failures with a consistent tag, and surface user-facing messages via `UiState.latestMessage` and a Snackbar. - `handleFailure` extension centralises failure logging and message surfacing while respecting coroutine cancellation. Build - Adds Compose, Navigation, Koin, Material Icons and lifecycle-viewmodel dependencies; enables Compose compiler and removes obsolete dimens/layouts from `build.gradle` and resources.
There was a problem hiding this comment.
Pull request overview
Rewrites the sample app from legacy Java/XML to a Kotlin + Jetpack Compose implementation that demonstrates the SumUp Reader SDK using a Clean Architecture split (domain/data/presentation) and Koin wiring.
Changes:
- Migrates UI to Compose with navigation, theming, and three primary screens (Welcome/Checkout/Settings).
- Introduces domain models + use-cases, plus a repository implementation that wraps SumUp SDK callbacks into coroutines with mappers.
- Updates build + resources (Compose/Koin deps, adaptive launcher icons, new strings, removes legacy layouts/dimens).
Reviewed changes
Copilot reviewed 53 out of 60 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| build.gradle | Updates build tooling dependencies (AGP/Kotlin plugin). |
| app/build.gradle | Enables Kotlin/Compose and adds Compose, Navigation, Koin, lifecycle, coroutines deps. |
| app/src/main/AndroidManifest.xml | Updates application/activity wiring for new Kotlin application + Compose activity and launcher icons. |
| app/src/main/java/com/sumup/app/SampleApplication.kt | New Application that initializes SumUpState and starts Koin. |
| app/src/main/java/com/sumup/sdksampleapp/SampleApplication.java | Removes legacy Java Application class. |
| app/src/main/java/com/sumup/sdksampleapp/MainActivity.java | Removes legacy Java/XML Activity implementation. |
| app/src/main/res/layout/activity_main.xml | Removes legacy XML layout. |
| app/src/main/res/values/strings.xml | Adds Compose UI strings for screens/settings/dialogs. |
| app/src/main/res/values/dimens.xml | Removes legacy dimens resource. |
| app/src/main/res/values-w820dp/dimens.xml | Removes tablet-specific legacy dimens override. |
| app/src/main/res/values/colors.xml | Adds launcher background color resource. |
| app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml | Adds adaptive launcher icon definition. |
| app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml | Adds adaptive round launcher icon definition. |
| app/src/main/res/drawable/ic_launcher_background.xml | Adds new launcher icon background drawable. |
| app/src/main/res/drawable/ic_launcher_foreground.xml | Adds new launcher icon foreground vector. |
| app/src/main/res/drawable/ic_sumup_logo.xml | Adds SumUp logo vector used on welcome screen. |
| app/src/main/res/drawable/ic_settings_gear.xml | Adds settings icon for checkout top bar. |
| app/src/main/res/drawable/ic_location_pin.xml | Adds location pin vector used on welcome screen. |
| app/src/main/res/drawable/ic_close.xml | Adds close icon vector (resource set). |
| app/src/main/res/drawable-nodpi/bg_welcome_map.webp | Adds welcome screen background image asset. |
| app/src/main/java/com/sumup/app/di/KoinModules.kt | Defines DI graph: dispatchers, mappers, repository, use cases, ViewModel. |
| app/src/main/java/com/sumup/app/util/CoroutinesDispatcherProvider.kt | Adds dispatcher abstraction for testability. |
| app/src/main/java/com/sumup/app/util/SafeResult.kt | Adds safe Result wrappers for logging + cancellation-aware error handling. |
| app/src/main/java/com/sumup/app/util/ResultExt.kt | Adds Result failure handling helper to surface messages. |
| app/src/main/java/com/sumup/app/data/repository/ReaderSdkRepositoryImpl.kt | Implements SDK repository, wrapping callbacks into suspend functions and mapping SDK models. |
| app/src/main/java/com/sumup/app/data/mapper/MerchantInfoMapper.kt | Maps SDK merchant to domain MerchantInfo. |
| app/src/main/java/com/sumup/app/data/mapper/ConnectedReaderMapper.kt | Maps SDK reader details to domain ConnectedReader/ReaderType. |
| app/src/main/java/com/sumup/app/data/mapper/OfflineSessionMapper.kt | Maps SDK offline session state to domain OfflineSession. |
| app/src/main/java/com/sumup/app/domain/repository/ReaderSdkRepository.kt | Introduces domain repository interface for SDK operations. |
| app/src/main/java/com/sumup/app/domain/model/MerchantInfo.kt | Adds pure domain model for merchant info. |
| app/src/main/java/com/sumup/app/domain/model/ConnectedReader.kt | Adds pure domain model for connected reader info. |
| app/src/main/java/com/sumup/app/domain/model/ReaderType.kt | Adds domain enum for reader type display mapping. |
| app/src/main/java/com/sumup/app/domain/model/CheckoutConfiguration.kt | Adds domain config model for checkout behavior and tipping. |
| app/src/main/java/com/sumup/app/domain/model/OfflineSession.kt | Adds domain model for offline session state + UI cap constant. |
| app/src/main/java/com/sumup/app/domain/model/OfflineSdkError.kt | Adds typed exceptions for offline operation failures. |
| app/src/main/java/com/sumup/app/domain/model/SdkResult.kt | Adds unified domain representation of SDK activity results. |
| app/src/main/java/com/sumup/app/domain/usecase/CreateLoginRequestUseCase.kt | Creates SumUpLogin request as a use case. |
| app/src/main/java/com/sumup/app/domain/usecase/CreateCheckoutRequestUseCase.kt | Builds SumUpPayment request from UI state + config. |
| app/src/main/java/com/sumup/app/domain/usecase/ParseSdkStatusUseCase.kt | Parses login/card-reader-page status bundles into SdkResult.Status. |
| app/src/main/java/com/sumup/app/domain/usecase/ParsePaymentResultUseCase.kt | Parses checkout result bundles into SdkResult.Payment. |
| app/src/main/java/com/sumup/app/presentation/model/UiState.kt | Adds single StateFlow-backed UI state for app screens. |
| app/src/main/java/com/sumup/app/presentation/model/UiEvent.kt | Adds UI events for navigation and executing SDK actions. |
| app/src/main/java/com/sumup/app/presentation/model/SdkActionRequest.kt | Defines presentation-level requests for SDK operations (login/checkout/card reader page). |
| app/src/main/java/com/sumup/app/presentation/navigation/Route.kt | Defines type-safe route constants for Compose navigation. |
| app/src/main/java/com/sumup/app/presentation/MainViewModel.kt | Implements app ViewModel: state, events, SDK result parsing, offline operations, settings. |
| app/src/main/java/com/sumup/app/presentation/MainActivity.kt | Hosts Compose UI, collects events, drives navigation and SDK action dispatch. |
| app/src/main/java/com/sumup/app/presentation/theme/Theme.kt | Adds Material3 color scheme + typography mapping into MaterialTheme. |
| app/src/main/java/com/sumup/app/presentation/theme/Type.kt | Defines custom text styles used across screens/components. |
| app/src/main/java/com/sumup/app/presentation/theme/SystemBars.kt | Adds helper to control system bar icon appearance. |
| app/src/main/java/com/sumup/app/presentation/screen/WelcomeScreen.kt | Implements welcome screen UI. |
| app/src/main/java/com/sumup/app/presentation/screen/CheckoutScreen.kt | Implements checkout screen UI (amount, keypad, status badges, result dialog). |
| app/src/main/java/com/sumup/app/presentation/screen/SettingsScreen.kt | Implements settings UI (tipping/offline/dev options/account). |
| app/src/main/java/com/sumup/app/presentation/screen/components/AmountDisplay.kt | Adds autosizing amount display component. |
| app/src/main/java/com/sumup/app/presentation/screen/components/Keypad.kt | Adds custom keypad component. |
| app/src/main/java/com/sumup/app/presentation/screen/components/CheckoutResultDialog.kt | Adds debug/result dialog component for SDK outcomes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…edReaderFlow for polling reader status
| } | ||
| dependencies { | ||
| classpath 'com.android.tools.build:gradle:8.8.2' | ||
| classpath 'com.android.tools.build:gradle:8.9.1' |
There was a problem hiding this comment.
Can we use kotlin for all gradle files?
|
|
||
| android { | ||
| namespace "com.sumup.sdksampleapp" | ||
| namespace "com.sumup.app" |
There was a problem hiding this comment.
just to make sure it does not clash with any Sumup package names, maybe: com.sumup.sample.app
|
|
||
| dependencies { | ||
| implementation 'com.google.android.gms:play-services-location:21.3.0' | ||
| implementation platform('androidx.compose:compose-bom:2024.10.01') |
There was a problem hiding this comment.
Can we use latest dependencies for the sample app?
| debug { | ||
| // All ProGuard rules required by the SumUp SDK are packaged with the library | ||
| minifyEnabled true | ||
| proguardFiles getDefaultProguardFile('proguard-android.txt') |
There was a problem hiding this comment.
Can we replace with proguard-android-optimize.txt?
| dependencies { | ||
| classpath 'com.android.tools.build:gradle:8.8.2' | ||
| classpath 'com.android.tools.build:gradle:8.9.1' | ||
| classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25' |
There was a problem hiding this comment.
Can we also use the latest version for gradle and kotlin plugins?
| .getOrDefault(false) | ||
| if (loggedIn) { | ||
| refreshMerchantStateInternal() | ||
| _events.trySend(UiEvent.NavigateToCheckout) |
There was a problem hiding this comment.
We can change all trySends to send(), as trySend might fail silently.
| import org.koin.androidx.viewmodel.dsl.viewModel | ||
| import org.koin.dsl.module | ||
|
|
||
| internal val appModule = module { |
There was a problem hiding this comment.
Since there is only one module for the whole app, we can rename the file to KoinModule.
| internal val appModule = module { | ||
| single<CoroutinesDispatcherProvider> { DefaultCoroutinesDispatcherProvider() } | ||
|
|
||
| single { OfflineSessionMapper() } |
There was a problem hiding this comment.
Nit: As these are stateless mappers, we can change to factory
| import java.math.BigDecimal | ||
| import java.util.UUID | ||
|
|
||
| internal class CreateCheckoutRequestUseCase( |
There was a problem hiding this comment.
Random place: Should we also cover the main logics with tests?
| onBackspace: () -> Unit, | ||
| onDoubleZeroPressed: () -> Unit, | ||
| ) { | ||
| val rows = listOf( |
There was a problem hiding this comment.
The list is rebuilt with each recomposition. Maybe hoisting it?
Replaces the legacy Java/XML sample app (MainActivity.java, SampleApplication.java, activity_main.xml, PNG launcher icons, w820dp resources) with a modern Kotlin and Jetpack Compose implementation that demonstrates the SumUp Reader SDK using a layered, testable architecture.
Architecture
presentation/layers, each holding only framework-appropriate types.ReaderSdkRepositoryinterface, pure Kotlin models (MerchantInfo,ConnectedReader,ReaderType,OfflineSession,OfflineSdkError,SdkResult,CheckoutConfiguration) and foursuspend-enabled use cases (CreateLoginRequestUseCase,CreateCheckoutRequestUseCase,ParseSdkStatusUseCase,ParsePaymentResultUseCase), all returningResult<T>viarunCatching.ReaderSdkRepositoryImplwraps the SumUp SDK callbacks as coroutines and delegates conversion to dedicated mappers (MerchantInfoMapper,ConnectedReaderMapper,OfflineSessionMapper).MainViewModelexposingStateFlow<UiState>+Channel<UiEvent>drives three Compose screens —WelcomeScreen,CheckoutScreen,SettingsScreen— composed fromAmountDisplay,KeypadandCheckoutResultDialog.SdkActionRequestlives in the presentation layer so SumUp SDK types never leak into domain.NavHostwith type-safe routes (Welcome,Checkout,Settings) hosted inside aScaffoldwhose padding is propagated down.di/KoinModules.kt; a coroutine dispatcher abstraction (CoroutinesDispatcherProvider+DefaultCoroutinesDispatcherProvider) keeps the ViewModel testable.UI / UX
enableEdgeToEdge(); screens applystatusBarsPadding()andnavigationBarsPadding()and manage system bar icon tint with aSystemBarsAppearancehelper.theme/(SparkBlue,Violet,LightSand, …) and typography scale (AmountTextStyle,ButtonLabelStyle, …) plugged intoMaterialTheme'sTypographyslot for consistent Material3 defaults.Buttonwhoseenabledstate is bound toisLoggedIn && amountInCents > 0.ic_launcher+ foreground/background vectors),ic_settings_gear,ic_close,ic_location_pin,ic_sumup_logo, and abg_welcome_mapwelcome background.Error handling & observability
SafeResult.safely/safelySuspendwrap SDK calls, log failures with a consistent tag, and surface user-facing messages viaUiState.latestMessageand a Snackbar.handleFailureextension centralises failure logging and message surfacing while respecting coroutine cancellation.Build
build.gradleand resources.