Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Conference-app-2024の良さげな実装を勝手にいくつか紹介する

gotlin
October 23, 2024
47

 Conference-app-2024の良さげな実装を勝手にいくつか紹介する

gotlin

October 23, 2024
Tweet

Transcript

  1. 10 Full Compose UI @Composable fun TimetableScreen( viewModel: TimetableViewModel =

    viewModel(), ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value TimetableScreen( uiState = uiState, ) }
  2. 11 Full Compose UI @Composable fun TimetableScreen( viewModel: TimetableViewModel =

    viewModel(), ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value TimetableScreen( uiState = uiState, ) } @Composable fun TimetableScreen( uiState: TimetableScreenUiState = timetableScreenPresenter(), ) { TimetableScreen( uiState = uiState, }
  3. 12 Full Compose UI @Composable fun TimetableScreen( viewModel: TimetableViewModel =

    viewModel(), ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle().value TimetableScreen( uiState = uiState, ) } @Composable fun TimetableScreen( uiState: TimetableScreenUiState = timetableScreenPresenter(), ) { TimetableScreen( uiState = uiState, }
  4. 13 Full Compose Presenter @Composable fun timetableScreenPresenter( sessionsRepository: SessionsRepository =

    localSessionsRepository(), ): TimetableScreenUiState { val sessions by rememberUpdatedState(sessionsRepository.timetable()) var timetableUiType by rememberRetained { mutableStateOf(List) } ... return TimetableScreenUiState(timetableUiState, timetableUiType) }
  5. 14 Full Compose Presenter @Composable fun timetableScreenPresenter( sessionsRepository: SessionsRepository =

    localSessionsRepository(), ): TimetableScreenUiState { val sessions by rememberUpdatedState(sessionsRepository.timetable()) var timetableUiType by rememberRetained { mutableStateOf(List) } ... return TimetableScreenUiState(timetableUiState, timetableUiType) }
  6. 15 Full Compose Presenter @Composable fun timetableScreenPresenter( sessionsRepository: SessionsRepository =

    localSessionsRepository(), ): TimetableScreenUiState { val sessions by rememberUpdatedState(sessionsRepository.timetable()) var timetableUiType by rememberRetained { mutableStateOf(List) } ... return TimetableScreenUiState(timetableUiState, timetableUiType) }
  7. 16 Full Compose Presenter @Composable fun timetableScreenPresenter( sessionsRepository: SessionsRepository =

    localSessionsRepository(), ): TimetableScreenUiState { val sessions by rememberUpdatedState(sessionsRepository.timetable()) var timetableUiType by rememberRetained { mutableStateOf(List) } ... return TimetableScreenUiState(timetableUiState, timetableUiType) }
  8. 17 Full Compose Presenter @Composable fun timetableScreenPresenter( sessionsRepository: SessionsRepository =

    localSessionsRepository(), ): TimetableScreenUiState { val sessions by rememberUpdatedState(sessionsRepository.timetable()) var timetableUiType by rememberRetained { mutableStateOf(List) } ... return TimetableScreenUiState(timetableUiState, timetableUiType) }
  9. 18 Full Compose Repository interface SessionsRepository { @Composable fun timetable():

    Timetable @Composable fun timetableItemWithBookmark( id: TimetableItemId ): Pair<TimetableItem, Boolean>? fun toggleBookmark(id: TimetableItemId) }
  10. 24 回転や遷移でデータ保持 Rinを使う @Composable fun Counter() { var count by

    remember { mutableIntStateOf(0) } var count by rememberRetained { mutableIntStateOf(0) } Button( onClick = { count++ } ) { Text(text = "Count: $count") } }
  11. 28 RepositoryのDI Presenter @Composable fun timetableScreenPresenter( sessionsRepository: SessionsRepository = localSessionsRepository(),

    ): TimetableScreenUiState { ... return TimetableScreenUiState(timetableUiState, timetableUiType) } UI Repository
  12. 29 RepositoryのDI Presenter @Composable fun timetableScreenPresenter( sessionsRepository: SessionsRepository = localSessionsRepository(),

    ): TimetableScreenUiState { ... return TimetableScreenUiState(timetableUiState, timetableUiType) } UI Repository
  13. 30 RepostoryのDI Multibindings interface SessionsRepository { @Composable fun timetable(): Timetable

    @Composable fun timetableItemWithBookmark( id: TimetableItemId ): Pair<TimetableItem, Boolean>? fun toggleBookmark(id: TimetableItemId) } class DefaultSessionsRepository: SessionsRepository { ... }
  14. 34 RepostoryのDI Multibindings @Module @InstallIn(SingletonComponent::class) object MyModule { @Provides @IntoMap

    @IntKey(1) fun provideInt1(): String { return "1" } @Provides @IntoMap @IntKey(2) fun provideInt2(): String { return "2" } }
  15. 35 RepostoryのDI Multibindings @Module @InstallIn(SingletonComponent::class) object MyModule { @Provides @IntoMap

    @IntKey(1) fun provideInt1(): String { return "1" } @Provides @IntoMap @IntKey(2) fun provideInt2(): String { return "2" } }
  16. 36 RepostoryのDI Multibindings @AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject

    lateinit var intMap: Map<Int, String> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) println(intMap) // {1="1", 2="2"} } }
  17. 37 RepostoryのDI Multibindings @AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject

    lateinit var intMap: Map<Int, String> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) println(intMap) // {1="1", 2="2"} } }
  18. 41 RepostoryのDI Multibindings @AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject

    lateinit var repositories: Map<Class<out Any>, @JvmSuppressWildcards Any> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) println(repositories) } }
  19. 42 RepostoryのDI Multibindings @AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject

    lateinit var repositories: Map<Class<out Any>, @JvmSuppressWildcards Any> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) println(repositories) } }
  20. 44 RepostoryのDI CompositionLocal @Composable fun MyComposable(context: Context) { // Use

    context } @Composable fun MyComposable() { val context = LocalContext.current // Use context }
  21. 45 RepostoryのDI CompositionLocal val LocalRepositories = compositionLocalOf<Map<KClass<*>, Any>> { error("No

    LocalRepository provided") } // Use MyRepository in Compose LocalRepositories.current[MyRepository::class] as MyRepository
  22. 46 RepostoryのDI CompositionLocal class RepositoryProvider @Inject constructor( repositories: Map<Class<out Any>,

    @JvmSuppressWildcards Any>, ) { private val repositoriesMap = repositories .map { (k, v) -> k.kotlin to v as Any }.toMap() @Composable fun Provide(content: @Composable () -> Unit) { CompositionLocalProvider( LocalRepositories provides repositoriesMap, ) { content() } } } }
  23. 47 RepostoryのDI CompositionLocal class RepositoryProvider @Inject constructor( repositories: Map<Class<out Any>,

    @JvmSuppressWildcards Any>, ) { private val repositoriesMap = repositories .map { (k, v) -> k.kotlin to v as Any }.toMap() @Composable fun Provide(content: @Composable () -> Unit) { CompositionLocalProvider( LocalRepositories provides repositoriesMap, ) { content() } } } }
  24. 48 RepostoryのDI CompositionLocal class RepositoryProvider @Inject constructor( repositories: Map<Class<out Any>,

    @JvmSuppressWildcards Any>, ) { private val repositoriesMap = repositories .map { (k, v) -> k.kotlin to v as Any }.toMap() @Composable fun Provide(content: @Composable () -> Unit) { CompositionLocalProvider( LocalRepositories provides repositoriesMap, ) { content() } } } }
  25. 49 RepostoryのDI CompositionLocal @AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject

    lateinit var repositoryProvider: RepositoryProvider override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { repositoryProvider.Provide { // Use Repository val myRepository = localSessionsRepository() } } } } @Composable fun localSessionsRepository(): SessionsRepository { return LocalRepositories.current[SessionsRepository::class] as SessionsRepository }
  26. 50 RepostoryのDI CompositionLocal @AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject

    lateinit var repositoryProvider: RepositoryProvider override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { repositoryProvider.Provide { // Use Repository val myRepository = localSessionsRepository() } } } } @Composable fun localSessionsRepository(): SessionsRepository { return LocalRepositories.current[SessionsRepository::class] as SessionsRepository }
  27. 51 RepostoryのDI CompositionLocal @AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject

    lateinit var repositoryProvider: RepositoryProvider override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { repositoryProvider.Provide { // Use Repository val myRepository = localSessionsRepository() } } } } @Composable fun localSessionsRepository(): SessionsRepository { return LocalRepositories.current[SessionsRepository::class] as SessionsRepository }
  28. 52 RepostoryのDI CompositionLocal @AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject

    lateinit var repositoryProvider: RepositoryProvider override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { repositoryProvider.Provide { // Use Repository val myRepository = localSessionsRepository() } } } } @Composable fun localSessionsRepository(): SessionsRepository { return LocalRepositories.current[SessionsRepository::class] as SessionsRepository }
  29. 54 画面イベントの定義 sealed interface TimetableScreenEvent { data class Bookmark( val

    id: Int, val bookmarked: Boolean, ): TimetableScreenEvent data object UiTypeChange: TimetableScreenEvent }
  30. 55 画面イベントの定義 @Composable fun TimetableScreen( eventFlow: MutableSharedFlow<TimetableScreenEvent> = remember {

    MutableSharedFlow(extraBufferCapacity = 20) }, uiState: TimetableScreenUiState = timetableScreenPresenter( events = eventFlow ), ) { TimetableScreen( uiState = uiState, onTimetableUiChangeClick = { eventFlow.tryEmit(TimetableScreenEvent.UiTypeChange) }, onBookmarked = { id -> eventFlow.tryEmit(TimetableScreenEvent.Bookmark(id)) }, ) }
  31. 56 画面イベントの定義 @Composable fun TimetableScreen( eventFlow: MutableSharedFlow<TimetableScreenEvent> = remember {

    MutableSharedFlow(extraBufferCapacity = 20) }, uiState: TimetableScreenUiState = timetableScreenPresenter( events = eventFlow ), ) { TimetableScreen( uiState = uiState, onTimetableUiChangeClick = { eventFlow.tryEmit(TimetableScreenEvent.UiTypeChange) }, onBookmarked = { id -> eventFlow.tryEmit(TimetableScreenEvent.Bookmark(id)) }, ) }
  32. 57 画面イベントの定義 @Composable fun TimetableScreen( eventFlow: MutableSharedFlow<TimetableScreenEvent> = remember {

    MutableSharedFlow(extraBufferCapacity = 20) }, uiState: TimetableScreenUiState = timetableScreenPresenter( events = eventFlow ), ) { TimetableScreen( uiState = uiState, onTimetableUiChangeClick = { eventFlow.tryEmit(TimetableScreenEvent.UiTypeChange) }, onBookmarked = { id -> eventFlow.tryEmit(TimetableScreenEvent.Bookmark(id)) }, ) }
  33. 58 画面イベントの定義 @Composable fun TimetableScreen( eventFlow: MutableSharedFlow<TimetableScreenEvent> = remember {

    MutableSharedFlow(extraBufferCapacity = 20) }, uiState: TimetableScreenUiState = timetableScreenPresenter( events = eventFlow ), ) { TimetableScreen( uiState = uiState, onTimetableUiChangeClick = { eventFlow.tryEmit(TimetableScreenEvent.UiTypeChange) }, onBookmarked = { id -> eventFlow.tryEmit(TimetableScreenEvent.Bookmark(id)) }, ) }
  34. 59 画面イベントの定義 @Composable fun timetableScreenPresenter( events: MutableSharedFlow<TimetableScreenEvent>, ... ): TimetableScreenUiState

    { ... LaunchedEffect(events) { events.collect { event -> launch { when (event) { is TimetableScreenEvent.Bookmark -> {} // Call repository function TimetableScreenEvent.UiTypeChange -> {} // Update retained state } } } } ... }