Skip to content

Commit

Permalink
Initial Kotlin and async/await support.
Browse files Browse the repository at this point in the history
  • Loading branch information
koush committed Jul 3, 2017
1 parent ce98c23 commit d22de06
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 17 deletions.
12 changes: 12 additions & 0 deletions ion-kotlin/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.koushikdutta.ion.kotlin"
android:versionCode="1"
android:versionName="1.0">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application>
</application>
</manifest>
46 changes: 46 additions & 0 deletions ion-kotlin/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'


dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile project(':ion:ion')
}

buildscript {
ext.kotlin_version = '1.1.3-eap-85'
repositories {
google()
jcenter()
maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1"}
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"


classpath project.hasProperty('global_gradleAndroidPlugin') ? global_gradleAndroidPlugin : 'com.android.tools.build:gradle:3.0.0-alpha5'
classpath 'com.google.gms:google-services:3.0.0'
classpath 'com.google.appengine:gradle-appengine-plugin:1.9.28'
}
}

android {
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
res.srcDirs = ['res/']
java.srcDirs = ['src/']
assets.srcDirs = ['assets/']
}
}

defaultConfig {
targetSdkVersion 26
minSdkVersion 14
}

compileSdkVersion project.hasProperty('global_compileSdkVersion') ? global_compileSdkVersion : 25
buildToolsVersion project.hasProperty('global_buildToolsVersion') ? global_buildToolsVersion : '25.0.2'
}

133 changes: 133 additions & 0 deletions ion-kotlin/src/com/koushikdutta/ion/kotlin/AsyncAwait.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package com.koushikdutta.ion.kotlin

import android.app.Activity
import android.app.Fragment
import android.app.Service
import android.content.Context
import android.os.Handler
import android.os.Looper
import com.koushikdutta.async.AsyncServer
import com.koushikdutta.async.future.Future
import com.koushikdutta.async.future.SimpleFuture
import com.koushikdutta.ion.ContextReference
import com.koushikdutta.ion.IonContext
import java.util.concurrent.Executor
import kotlin.coroutines.experimental.*

/**
* Created by koush on 7/2/17.
*/

private class WrappingContextReference {

}

fun <T> Activity.async(block: suspend AsyncContext.() -> T): Future<T> {
return async(ContextReference.ActivityContextReference(this) as ContextReference<Object>, block)
}

fun <T> Service.async(block: suspend AsyncContext.() -> T): Future<T> {
return async(ContextReference.ServiceContextReference(this) as ContextReference<Object>, block)
}

fun <T> Fragment.async(block: suspend AsyncContext.() -> T): Future<T> {
return async(ContextReference.FragmentContextReference(this) as ContextReference<Object>, block)
}

fun <T> android.support.v4.app.Fragment.async(block: suspend AsyncContext.() -> T): Future<T> {
return async(ContextReference.SupportFragmentContextReference(this) as ContextReference<Object>, block)
}

class AsyncContext(val ionContext: IonContext, val future: SimpleFuture<Object>): IonContext {
override fun getContext(): Context? {
return ionContext.context
}

override fun isAlive(): String? {
return ionContext.isAlive
}

suspend fun <T> Future<T>.await(): T {
return suspendCoroutine { continuation ->
setCallback { e, result ->
if (checkLive()) {
if (e != null)
continuation.resumeWithException(e);
else
continuation.resume(result);
}
}
}
}

suspend fun await(looper: Looper) {
return await(Handler(looper))
}

suspend fun await() {
return await(Looper.getMainLooper())
}

suspend fun await(handler: Handler) {
return suspendCoroutine { continuation ->
handler.post {
if (checkLive())
continuation.resume(Unit)
}
}
}

suspend fun await(asyncServer: AsyncServer) {
return suspendCoroutine { continuation ->
asyncServer.post {
if (checkLive())
continuation.resume(Unit)
}
}
}

suspend fun await(executor: Executor) {
return suspendCoroutine { continuation ->
executor.execute {
if (checkLive())
continuation.resume(Unit)
}
}
}

fun checkLive(): Boolean {
if (isAlive == null)
return true
future.cancelSilently()
return false
}
}

private class StandaloneCoroutine<T>(val asyncContext: AsyncContext, val future: SimpleFuture<T>, override val context: CoroutineContext): Continuation<T> {
override fun resume(value: T) {
if (asyncContext.isAlive() == null)
future.setComplete(value)
else
future.cancelSilently()
}

override fun resumeWithException(exception: Throwable) {
if (asyncContext.isAlive() == null) {
if (exception is Exception)
future.setComplete(exception)
else
future.setComplete(Exception(exception))
}
else {
future.cancelSilently()
}
}
}

internal fun <T> async(ionContext: IonContext, block: suspend AsyncContext.() -> T): Future<T> {
val future = SimpleFuture<T>()
val asyncContext = AsyncContext(ionContext, future as SimpleFuture<Object>)
val coroutineContext = StandaloneCoroutine<T>(asyncContext, future, EmptyCoroutineContext)
block.startCoroutine(asyncContext, coroutineContext)
return future
}
7 changes: 5 additions & 2 deletions ion-sample/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
android:icon="@drawable/ic_launcher"
android:theme="@style/Theme">
<activity
android:name=".Twitter"
android:label="Twitter Client Sample"/>
android:name=".Twitter"
android:label="Twitter Client Sample"/>
<activity
android:name=".TwitterKotlin"
android:label="Twitter Kotlin Client Sample"/>
<activity
android:name=".TwitterGson"
android:label="Twitter Gson Client Sample"/>
Expand Down
21 changes: 12 additions & 9 deletions ion-sample/build.gradle
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
buildscript {
ext.kotlin_version = '1.1.3-eap-85'
repositories {
google()
jcenter()
maven { url "https://dl.bintray.com/kotlin/kotlin-eap-1.1"}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'
}
}
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

allprojects {
repositories {
jcenter()

classpath project.hasProperty('global_gradleAndroidPlugin') ? global_gradleAndroidPlugin : 'com.android.tools.build:gradle:3.0.0-alpha5'
classpath 'com.google.gms:google-services:3.0.0'
classpath 'com.google.appengine:gradle-appengine-plugin:1.9.28'
}
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

dependencies {
compile 'com.makeramen:roundedimageview:+'
compile 'com.github.chrisbanes.photoview:library:+'
compile 'com.flaviofaria:kenburnsview:1.0.6'
// compile project(':ion:ion')
compile project (':ion:ion')
compile project (':ion:ion-kotlin')

compile 'com.google.android.gms:play-services-base:11.0.0'

compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

android {
Expand Down
6 changes: 6 additions & 0 deletions ion-sample/res/layout/samples.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
android:layout_height="wrap_content"
android:text="Twitter Client Sample" />

<Button
android:id="@+id/twitter_kotlin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Twitter Kotlin Client Sample" />

<Button
android:id="@+id/twitter_gson"
android:layout_width="match_parent"
Expand Down
8 changes: 8 additions & 0 deletions ion-sample/src/com/koushikdutta/ion/sample/Samples.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ public void onClick(View v) {
}
});

Button twitterKotlin = (Button)findViewById(R.id.twitter_kotlin);
twitterKotlin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(Samples.this, TwitterKotlin.class));
}
});

Button twitterGson = (Button)findViewById(R.id.twitter_gson);
twitterGson.setOnClickListener(new View.OnClickListener() {
@Override
Expand Down
6 changes: 0 additions & 6 deletions ion-sample/src/com/koushikdutta/ion/sample/Twitter.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package com.koushikdutta.ion.sample;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
Expand All @@ -20,7 +15,6 @@
import com.koushikdutta.async.future.Future;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import com.koushikdutta.ion.bitmap.Transform;

public class Twitter extends Activity {
// adapter that holds tweets, obviously :)
Expand Down
Loading

0 comments on commit d22de06

Please sign in to comment.