Need help with conference-app-2019?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

DroidKaigi
818 Stars 288 Forks Apache License 2.0 2.1K Commits 43 Opened issues

Description

The Official Conference App for DroidKaigi 2019 Tokyo

Services available

!
?

Need anything else?

Contributors list

DroidKaigi 2019 official Android app CircleCI

DroidKaigi 2019 is a conference tailored for developers on 7th and 8th February 2019.

You can install the prodution app via Get it on Google Play.

And also, you can try the binary under development built on master branch through Try it on your device via DeployGate

NOTE: Google Play Protect will show a warning dialog on some of devices when installing the current apk. The detailed specification of Google Play Protect is not public so we cannot address this matter. Please ignore the dialog for now. If you cannot install this apk without any error message, please disable Google Play Protect from Google Play Store's menus. Sorry for the inconvenience.

Features

| top | timetable | search | |---|---|---| | image | image | image |

  • View conference schedule and details of each session
  • Set notification for upcoming sessions on your preference
  • Search sessions and speakers and topics
  • Show Information Feed

Contributing

We always welcome any and all contributions! See CONTRIBUTING.md for more information

We would be happy if you ran the command below before sending pull requests to install git hooks. Thanks.

./scripts/git/install.bash

Requirements

  • Android Studio 3.4 Beta 3 and higher. You can download it from this page.
  • Android Studio Kotlin Plugin v1.3.20-release-Studio

Check out following status.

  • Use recent version of Android Studio Kotlin Plugin

Preferences
>
Languages & Frameworks
>
Kotlin Updates

Older versions of the Kotlin plugin may cause build failures. If you still have a trouble after upgrading the plugin, please try using AndroidStudio 3.4 instead.

  • Disable Instant Run

Preferences
>
Build, Execution, Deployment
>
Instant Run
> Uncheck
Enable Instant Run

Development Environment

Multi module project

We separate the modules for each feature.

image

You can check generated module dependency diagram

Unidirectional data flow(Flux-based) Architecture

Unidirectional data flow(Flux-based) Architecture with

Kotlin Coroutines
and
AndroidX
Libraries(
LiveData
,
ViewModel
,
Room
)
DataBinding
,
Dagger
and
AssistedInject
,
Firebase
etc.

Kotlin Multiplatform Project

You can check the iOS application.

The API and Model parts are shared as

Kotlin Multiplatform
, written in
Kotlin
, and the other part is written in
Swift
.

You can check How to build for iOS Application

Groupie

By using

Groupie
you can simplify the implementation around RecyclerView.
class SpeakerItem @AssistedInject constructor(
    @Assisted val speaker: Speaker, // Inject by AssistedInject
    val navController: NavController // Inject by Dagger
) : BindableItem() {
    @AssistedInject.Factory
    interface Factory {
        fun create(
            speaker: Speaker
        ): SpeakerItem
    }

override fun getLayout(): Int = R.layout.item_speaker

override fun bind(itemBinding: ItemSpeakerBinding, position: Int) {
    itemBinding.speakerText.text = speaker.name
    ...
}

}

We use

AssistedInject
for creating item.
    @Inject lateinit var speakerItemFactory: SpeakerItem.Factory

... val speakerItems = session .speakers .map { speakerItemFactory.create(it) } groupAdapter.update(speakerItems)

Architecture

Unidirectional data flow(Flux-based) Architecture with Kotlin Coroutines and AndroidX Libraries(LiveData, ViewModel, Room) DataBinding, dependency injection, Firebase etc.

Activity/Fragment -> Action Creator

image

Fragments just call Action Creator's method.

class SessionPagesFragment : DaggerFragment() {
    @Inject lateinit var announcementActionCreator: AnnouncementActionCreator
    override fun onActivityCreated(savedInstanceState: Bundle?) {
    ...
        announcementActionCreator.load()
    }

Action Creator <-> DB / API and Action Creator -> dispatcher

image

Action Creator fetches data from DB / API with

Kotlin Coroutines suspend function
. And Action Creator dispatches data loaded action and loading state changed actions.
class AnnouncementActionCreator @Inject constructor(
    override val dispatcher: Dispatcher,
    val firestore: Firestore,
    @PageScope val lifecycle: Lifecycle
) : CoroutineScope by lifecycle.coroutineScope,
    ErrorHandler {

fun load() = launch {
    try {
        dispatcher.dispatch(Action.AnnouncementLoadingStateChanged(LoadingState.LOADING))
        // fetch announcement by Kotlin Coroutines suspend function
        dispatcher.dispatch(Action.AnnouncementLoaded(firestore.getAnnouncements()))
        dispatcher.dispatch(Action.AnnouncementLoadingStateChanged(LoadingState.LOADED))
    } catch (e: Exception) {
        onError(e)
        dispatcher.dispatch(Action.AnnouncementLoadingStateChanged(LoadingState.INITIALIZED))
    }
}

}

Actions are just data holder class.

sealed class Action {
...
    class AnnouncementLoadingStateChanged(val loadingState: LoadingState) : Action()
    class AnnouncementLoaded(val announcements: List) : Action()
...
}

Dispatcher -> Store

image

Store subscribe dispatcher's action with

Kotlin Coroutines channel
and transform it to AndroidX
LiveData
. This store is a
ViewModel
. But if the store is used by the whole application(ex: UserStore), you can change the store to a singleton.
class AnnouncementStore @Inject constructor(
    dispatcher: Dispatcher
) : Store() {
    val loadingState: LiveData = dispatcher
        .subscribe()
        .map { it.loadingState }
        .toLiveData(this, LoadingState.LOADING)
    val announcements: LiveData> = dispatcher
        .subscribe()
        .map { it.announcements }
        .toLiveData(this, listOf())
}

Store -> Activity/Fragment

image

In the fragment, we can observe Store's

LiveData
. You can display the UI with
LiveData
.
    override fun onActivityCreated(savedInstanceState: Bundle?) {
...
        announcementStore.loadingState.changed(viewLifecycleOwner) {
            // apply loading state for progress bar
            progressTimeLatch.loading = it == LoadingState.LOADING
        }
        announcementStore.announcements.changed(viewLifecycleOwner) { announcements ->
            // we can show UI with announcements
        }
...

Thanks

Thank you for contributing!

Credit

This project uses some modern Android libraries and source codes.

Android

iOS

  • Kotlin/Native
  • MaterialComponents
  • ReactiveX/RxSwift
  • SnapKit/SnapKit
  • onevcat/Kingfisher
  • SwiftLint
  • LicensePlist
  • XLPagerTabStrip

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.