Skip to content

Conversation

@nimi0112
Copy link

Continue Compose migration: LoginScreen and ProxySettings (Part 3)
1st PR: #2991
2nd PR:#3025

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-ios and hybrids

Motivation

Migrate LogsScreen from Fragment-based architecture to modern Jetpack Compose as part of the ongoing effort to modernize the Tester app.

This continues the migration pattern established with LoginScreen and ConfigureScreen, reducing technical debt.

Description

Changes Made

New Compose Implementation:

  • LogsScreen.kt - Material3 Compose UI with Scaffold, TopAppBar, and LazyColumn
  • LogsViewModel.kt - StateFlow-based ViewModel with interface pattern
  • LogsScreenState.kt- Sealed class for type-safe state management
  • LogsViewModelTest.kt - Comprehensive unit tests (7 test cases)

UI Features:

  • Material3 TopAppBar with back navigation
  • LazyColumn for efficient log list rendering
  • Color-coded log backgrounds (VERBOSE/DEBUG=white, INFO=blue, WARN=yellow, ERROR=red)
  • Empty state message when no logs available
  • Dark theme support (automatic via Material3)

Navigation Updates:

  • Updated PurchaseTesterNavHost to use Compose navigation for logs route
  • Added NavigationExtras constants for type-safe Intent extras
  • Updated ConfigureActivity to handle direct navigation from OverviewFragment
  • Removed Fragment-based navigation from MainActivity

Code Cleanup:

  • Deleted LogsFragment.kt
  • Deleted fragment_logs.xml
  • Deleted log_row_view.xml
  • Cleaned up nav_graph.xml (removed logsFragment references)
  • Simplified MainActivity (removed unused navigation code)

Testing

Unit Tests (LogsViewModelTest.kt):

  • Initial state is Loading
  • loadLogs() transitions to LogsData with correct logs
  • Empty logs list handled correctly
  • All log levels work correctly (VERBOSE, DEBUG, INFO, WARN, ERROR)
  • Multiple calls to loadLogs() supported
  • StateFlow collects properly
output.video.mp4

…odule

Migrate ConfigureScreen to Jetpack Compose

- Add Compose theme system (Color, Type, Theme)
- Create ConfigureActivity as Compose entry point
- Add Compose dependencies to build config
- Add test cases for ConfigureScreenViewModel
Refactor ConfigureScreenViewModelImpl to use a reactive flow-based approach:
- Remove init block and loadData() method to eliminate side effects
- Transform _state from MutableStateFlow to derived StateFlow using combine()
- Add userEdits flow to track user modifications before persistence
- Use SharingStarted.WhileSubscribed() for lazy, lifecycle-aware data loading
- Extract subscription timeout as SUBSCRIPTION_TIMEOUT_MILLIS constant

Benefits:
- No side effects in constructor/init
- Data loads only when UI observes the state
- Better testability and lifecycle awareness
- Automatic cleanup when no observers
- Follows modern Android ViewModel best practices

All existing tests pass without modifications.
…ecture

Migrate LoginFragment to a fully Compose-based LoginScreen with type-safe
navigation architecture, following the patterns established in ConfigureScreen.

## LoginScreen Implementation

Created new Compose-based login screen with:
- LoginScreenState: Sealed class for state management with Loading and Data states
- LoginScreenViewModel: Reactive ViewModel using StateFlow with user edits pattern
- LoginScreen: Composable UI matching original fragment_login.xml layout exactly
- LoginScreenViewModelTest: Comprehensive unit tests (7 tests, all passing)

Key features:
- User ID input with automatic trimming
- Login with user ID using Purchases.logInWith()
- Continue as random user (handles both anonymous and logged-in states)
- Reset SDK functionality with Purchases.close()
- Type-safe event system for navigation and error handling
- String resources for all UI text (localization-ready)

## Navigation Architecture

Created type-safe Compose navigation:
- PurchaseTesterScreen: Sealed class defining all navigation routes
- PurchaseTesterNavHost: NavHost with hybrid Compose + Fragment navigation
- Smooth transitions between Configure and Login screens
- Proper back stack management with popUpTo configurations

Navigation flows:
- Configure → Login: Pure Compose navigation within ConfigureActivity
- Login → Overview: Intent to MainActivity (Fragment-based, until migrated)
- Login → Configure: Compose navigation with full stack clear
- Logs/Proxy: Fallback to Fragment navigation (until migrated)

## Cleanup and Updates

Deleted obsolete files:
- LoginFragment.kt (2,768 bytes)
- fragment_login.xml (4,217 bytes)

Updated existing files:
- ConfigureActivity: Now uses PurchaseTesterApp with NavHost
- MainActivity: Removed LOGIN navigation case (handled by Compose)
- OverviewFragment: Logout navigates to ConfigureActivity instead of LoginFragment
- nav_graph.xml: Removed all LoginFragment references, changed startDestination
- Constants.kt: Removed unused LOGIN constant

## Architecture Benefits

- Type-safe navigation with sealed classes (compile-time safety)
- Hybrid navigation allowing gradual migration of remaining screens
- Pattern consistency across all Compose screens
- Better testability with interface-based ViewModels
- Modern reactive state management
- Clean separation between Compose and Fragment screens

## Testing

- All unit tests passing (7/7)
- Build successful
- Feature parity with original LoginFragment verified
- Navigation flows tested and working correctly

This migration establishes the navigation architecture pattern for remaining
screen migrations and demonstrates best practices for Compose + Fragment hybrid
navigation during incremental migration.
    Implement new Compose-native ProxySettings bottom sheet to replace Fragment-based implementation for ConfigureScreen and
    LoginScreen.

    Changes:
    - Add ProxySettingsViewModel with StateFlow and coroutines
    - Add ProxySettingsSheet using Material3 ModalBottomSheet
    - Update PurchaseTesterNavHost to show sheet as modal overlay
    - Add comprehensive unit tests for ProxySettingsViewModel
    - Improve error messages with exception class name for debugging

    The old Fragment-based implementation remains untouched and continues to be used by OverviewFragment. It will be removed when
    OverviewScreen is migrated to Compose in a future PR.

    Technical details:
    - Uses StateFlow instead of LiveData for reactive state management
    - Coroutines with injectable dispatcher for testability
    - No init block - explicit loadCurrentState() method
    - Inline updateState function matching ConfigureScreenViewModel pattern
    - Unit tests covering all state transitions
Replace Fragment-based logs screen with modern Compose implementation following established patterns from LoginScreen and ConfigureScreen migrations.

Key changes:
- Add LogsScreen composable with Material3 components (Scaffold, TopAppBar, LazyColumn)
- Add LogsViewModel with StateFlow-based state management
- Add LogsScreenState sealed class for Loading and LogsData states
- Add comprehensive unit tests for LogsViewModel (7 test cases)
- Add Yellow and Blue colors to theme for log level backgrounds
- Add empty state message when no logs are available
- Update navigation to use Compose navigation instead of Fragment navigation
- Remove LogsFragment, fragment_logs.xml, and log_row_view.xml
- Clean up navigation graph references to logsFragment
- Add NavigationExtras constants for type-safe Intent extras
- Update ConfigureActivity to handle direct navigation to logs from OverviewFragment
- Simplify MainActivity by removing unused navigation handling

Benefits:
- More efficient rendering with LazyColumn vs RecyclerView
- Removed ~90 lines of adapter boilerplate
- Type-safe navigation with sealed classes
- Improved testability with pure ViewModel
- Consistent with other migrated Compose screens
- Better user experience with empty state handling
@nimi0112 nimi0112 requested a review from a team as a code owner January 19, 2026 03:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant