当前位置: 首页 > 软件库 > 手机/移动开发 > >

conference-app-2018

授权协议 Apache-2.0 License
开发语言 Kotlin
所属分类 手机/移动开发
软件类型 开源软件
地区 不详
投 递 者 慕阳文
操作系统 Android
开源组织
适用人群 未知
 软件概览

DroidKaigi 2018 official Android app

DroidKaigi 2018 is a conference tailored for developers on 8th and 9th February 2018.

Features

  • 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 are always welcome your contribution!

How to find the tasks

We use waffle.io to manage the tasks.Please find the issues you'd like to contribute in it.welcome contribute and easy are good for first contribution.

Of course, it would be great to send PullRequest which has no issue!

How to contribute

If you find the tasks you want to contribute, please comment in the issue like this to prevent to conflict contribution.We'll reply as soon as possible, but it's unnecessary to wait our reaction. It's okay to start contribution and send PullRequest!

We've designated these issues as good candidates for easy contribution. You can always fork the repository and send a pull request (on a branch other than master).

Development Environment

Kotlin

This app is full Kotlin!

RxJava2 & LiveData

Converting RxJava2's publisher to AAC LiveData with LiveDataReactiveStreams.

AllSessionsViewModel.kt

repository.sessions
    .toResult(schedulerProvider)
    .toLiveData()

LiveDataReactiveStreamsExt.kt

fun <T> Publisher<T>.toLiveData() = LiveDataReactiveStreams.fromPublisher(this)

Groupie

By using Groupie you can simplify the implementation around RecyclerView.

data class SpeakerItem(
        val speaker: Speaker
) : BindableItem<ItemSpeakerBinding>(speaker.id.hashCode().toLong()) {

    override fun bind(viewBinding: ItemSpeakerBinding, position: Int) {
        viewBinding.speaker = speaker
    }

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

Architecture

This app uses an Android Architecture Components(AAC) based architecture using AAC(LiveData, ViewModel, Room), Kotlin, RxJava, DataBinding, dependency injection, Firebase.

Fragment -> ViewModel

Use LifecycleObserver for telling lifecycle to ViewModel.

SessionsFragment.kt

class SessionsFragment : Fragment(), Injectable {

    private lateinit var sessionsViewModel: SessionsViewModel

...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        ...
        lifecycle.addObserver(sessionsViewModel)
        ...

SessionsViewModel.kt

class SessionsViewModel @Inject constructor(
        private val repository: SessionRepository,
        private val schedulerProvider: SchedulerProvider
) : ViewModel(), LifecycleObserver {
  ...
    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {
    ...
}

ViewModel -> Repository

Use RxJava2(RxKotlin) and ViewModel#onCleared() for preventing leaking.

SessionsViewModel.kt

private val compositeDisposable: CompositeDisposable = CompositeDisposable()

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {
        repository
                .refreshSessions()
                .subscribeBy(onError = defaultErrorHandler())
                .addTo(compositeDisposable)
    }

    override fun onCleared() {
        super.onCleared()
        compositeDisposable.clear()
    }

Repository -> API, Repository -> DB

Use Retrofit and save to the Architecture Component Room.

SessionDataRepository.kt

override fun refreshSessions(): Completable {
        return api.getSessions()
                .doOnSuccess { response ->
                    sessionDatabase.save(response)
                }
                .subscribeOn(schedulerProvider.computation())
                .toCompletable()
    }

DB -> Repository

Use Room with RxJava2 Flowable Support.And SessionDataRepository holds Flowable property.

SessionDao.kt

@Query("SELECT room_id, room_name FROM session GROUP BY room_id ORDER BY room_id")
    abstract fun getAllRoom(): Flowable<List<RoomEntity>>

SessionDataRepository.kt

class SessionDataRepository @Inject constructor(
        private val sessionDatabase: SessionDatabase,
...
) : SessionRepository {

    override val rooms: Flowable<List<Room>> =
            sessionDatabase.getAllRoom().toRooms()

Repository -> ViewModel

We create LiveData from a ReactiveStreams publisher with LiveDataReactiveStreams

SessionsViewModel.kt

val rooms: LiveData<Result<List<Room>>> by lazy {
        repository.rooms
                .toResult(schedulerProvider)
                .toLiveData()
    }

LiveDataReactiveStreamsExt.kt

fun <T> Publisher<T>.toLiveData() = LiveDataReactiveStreams.fromPublisher(this) as LiveData<T>

And using Result class for error handling with Kotlin extension.

fun <T> Flowable<T>.toResult(schedulerProvider: SchedulerProvider): Flowable<Result<T>> =
        compose { item ->
            item
                    .map { Result.success(it) }
                    .onErrorReturn { e -> Result.failure(e.message ?: "unknown", e) }
                    .observeOn(schedulerProvider.ui())
                    .startWith(Result.inProgress())
        }
sealed class Result<T>(val inProgress: Boolean) {
    class InProgress<T> : Result<T>(true)
    data class Success<T>(var data: T) : Result<T>(false)
    data class Failure<T>(val errorMessage: String?, val e: Throwable) : Result<T>(false)

ViewModel -> Fragment

Fragment observe ViewModel's LiveData.We can use the result with Kotlin when expression.In is Result.Success block, you can access data with result.data by Kotlin Smart cast.

SessionsFragment.kt

sessionsViewModel.rooms.observe(this, { result ->
            when (result) {
                is Result.InProgress -> {
                    binding.progress.show()
                }
                is Result.Success -> {
                    binding.progress.hide()
                    sessionsViewPagerAdapter.setRooms(result.data)
                }
                is Result.Failure -> {
                    Timber.e(result.e)
                    binding.progress.hide()
                }
            }
        })

Release

The release process is automated by using gradle-play-publisher.When we add git tag, CI deploys the release apk to GooglePlay alpha.To know more details, see .circleci/config.yml

elif [[ "${CIRCLE_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    echo "Deploy to Google Play"
    openssl aes-256-cbc -k $PUBLISHER_KEYS_JSON_DECRYPT_PASSWORD -d -in encrypted-publisher-keys.json -out app/publisher-keys.json
    ./gradlew publishApkRelease
fi

iOS App with Kotlin/Native and Kotlin Multiplatform Projects

Some contributors are challenging to develop iOS app with Kotlin/Native and Kotlin Multiplatform Projects.
We are watching this project.DroidKaigi2018iOS

DroidKaigi 2018 Flutter App

The unofficial conference app for DroidKaigi 2018 Tokyohttps://github.com/konifar/droidkaigi2018-flutter

Thanks

Thank you for contributing!

Credit

This project uses some modern Android libraries and source codes.

License

Copyright 2018 DroidKaigi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
  • 问题: ionic3 在执行命令 ionic serve 或者 ionic cordova build android 时,报错 Error: Cannot find module '@ionic/app-scripts'。这个问题的主要现象就是创建的项目node_modules文件夹中没有任何文件 解决方法: 一. 打开cmd。 二. 重装 ionic  1.卸载:npm uninstall -

  • 注意: 在app.vue onLaunch中调用webSocket这样可以一进入系统就开启webSocket。 步骤: 判断是否已连接 --> 如未连接 打开连接(已连接就跳过) --> 打开成功监听服务器返回的消息 -->前端用户跟服务器进行绑定 --> 监听到有新服务器消息,对服务器返回的新消息进行操作 --> 检测心跳 --> 心跳已停止重新连接websocket data() { ret

  • ionic-app 本APP是从 ionic-conference-app fork 而来, ionic4 + angular7 的集成环境,可用于商用 如果能帮到您,请留下您的star再走,谢谢! 目录说明 src ├─app\@core 核心控制 │ ├─control 基础页面类,使用者可继承 │ ├─data 权限控制、用户、状态类 │ ├─helpers 工具类 │ ├─i18n 语言类

  • Mobile App Security   1. DATA THEOREM LAB https://datatheorem.github.io/ Data Theorem's technical blog about mobile security and privacy. 2. Android安全中文站 http://www.droidsec.cn/ 3. hackoftheday hackof

  • 老司机 iOS 周报,只为你呈现有价值的信息。 你也可以为这个项目出一份力,如果发现有价值的信息、文章、工具等可以到 Issues 里提给我们,我们会尽快处理。记得写上推荐的理由哦。有建议和意见也欢迎到 Issues 提出。 福利 ? 我们发福利啦~ 周报已经快陪伴大家走过一年的时间,非常感谢各位朋友的支持和厚爱。为了在 2019 年能更好地为大家服务,我们举办了一个问卷调查活动。在 12 月 2

  • In simple words domain is the address of your sip server or an ip of the machine where your Sip server is running and sip server listens on 5060 and 5061 port by default . There are many openSource si

  • 原来app_conference 08年之后就没有更新了。app_conference是支持音频 视频会议的,但测试结果却是没有,可能是测试方法不对。 app_konference在app_conference的基础上继续开发的,主要优化了音频会议的音质,而且在版本1.7之后就没有视频功能了了,也就是2.x版本都是只有音频会议功能的。 经过测试(DELL CMDQ43X型服务器,Intel(R)

 相关资料
  • Conference App in a Box This is the React Native CLI version. To view the Expo version, click here. This repo goes along with my Dev.to post titled "Introducing Conference App in a Box" For a full wal

  • Conference Call A conference call implementation using WebRTC, Ratchet Web Socket. Getting Started Run composer install to install the dependencies. Set your web socket domain name and port in ws/bin/

  • 问题内容: 在socket.io网页上,位于: http://socket.io/get-started/chat/ 有这样的代码: 可以这样更清晰地重写它: socket.io示例使用http.Server()创建服务器。但是,app.listen()的快速文档显示了使用以下示例创建服务器的示例: app.listen() 绑定并侦听给定主机和端口上的连接。此方法与节点的http.Server#

  • app

    继承自 NativeObject 用于提供应用信息。 通过 “const {app} = require('tabris');” 引入该对象 示例: app.on("pause", () => pauseVideo()); 方法 getResourceLocation(path) 参数: path: string 资源相对于应用程序根目录的路径。 返回值: string 给定与app打包在一起的

  • App

    app是一个ionic的装饰器,它可以启动应用,是整个ionic应用的主入口。通过一系列的参数作为应用程序的全局配置变量。@App可以接受一个模板属性或者一个模板地址。 import {App} from 'ionic-angular'; @App({ templateUrl: 'app/app.html', providers: [DataService] }) export class

  • app

    app 模块是为了控制整个应用的生命周期设计的。 下面的这个例子将会展示如何在最后一个窗口被关闭时退出应用: var app = require('app'); app.on('window-all-closed', function() { app.quit(); }); 事件列表 app 对象会触发以下的事件: 事件:'will-finish-launching' 当应用程序完成基础的启