How to implement CanSnail for custom views?

44 views
Skip to first unread message

Austin Guest

unread,
Jun 13, 2015, 9:19:57 PM6/13/15
to mac...@googlegroups.com
Hi all. I'm working on a prototype for a location sharing app for activists.

The first user story is to enable a big red/green "go button" that:

(1) when pressed quickly will flash green add the user's location to a map viewable by all users.
(2) when long-pressed will turn (and stay) green whilst turning on passive-location sharing until long-pressed again (at which point it turns red again)

Cribbing off the excellent work of 47 Degrees, I cobbled together a basic custom CircleView class that works for case (2), but not for case (1). The problem is that case (1) requires that I combine a tweak on the custom view with a standard macroid `delay` snail -- which don't seem to know how to combine together. Specifically...

Given this tweak:
def cvColorChange(color: Int) = Tweak[CircleView] ({ cv ⇒  cv.invalidate(); cv.setColor(color) })
and this effort to snail it: 
goButton <~ cvColor(off) <~
On.click {
goButton <~ cvColorChange(off) <~~ delay(100) <~ cvColorChange(on)
} <~
i get this error message:
Don't know how to snail macroid.Ui[Option[org.tlc.whereat.ui.components.CircleView]] with macroid.Snail[android.view.View]. 
Try importing an instance of CanSnail[macroid.Ui[Option[org.tlc.whereat.ui.components.CircleView]], macroid.Snail[android.view.View], ...].

i made a few efforts to implement the implicits involved in CanSnail, but got very lost very quickly. can anyone help?

here are some links for:


for those who like long bits of code in emails, here is the same but in the email:

activity:
package org.tlc.whereat.ui.main

import android.app.Activity
import android.os.Bundle
import com.fortysevendeg.macroid.extras.ResourcesExtras._
import macroid.FullDsl._
import macroid.{Contexts, Ui}
import org.tlc.whereat.R
import org.tlc.whereat.ui.components.CircleView._

class MainActivity
extends Activity
with Contexts[Activity]
with MainLayout
with MainTweaks {

override def onCreate(savedInstanceState: Bundle) = {

super.onCreate(savedInstanceState)

setContentView(layout)

val off = resGetColor(R.color.go_button_off)
val on = resGetColor(R.color.go_button_on)

// runUi {
// goButton <~ cvColor(off) <~
// On.click {
// goButton <~ cvColorChange(off) <~~ delay(100) <~ cvColorChange(on)
// } <~
//
/*TODO:
* The call to `delay(100)` on line 34 above triggers the following error message:
*
* Don't know how to snail
* macroid.Ui[Option[org.tlc.whereat.ui.components.CircleView]] with macroid.Snail[android.view.View].
* Try importing an instance of
* CanSnail[macroid.Ui[Option[org.tlc.whereat.ui.components.CircleView]], macroid.Snail[android.view.View], ...].
*
* How can I fix this?
* */
On.longClick {
toastSharingStatus(goButton, on, off) ~
( goButton <~ toggleGoButton(on,off) ) ~
Ui(true)
}
}
}
}



layout:

package org.tlc.whereat.ui.main

import android.widget.LinearLayout
import macroid.FullDsl._
import macroid.{ActivityContext, AppContext}
import org.tlc.whereat.ui.components.CircleView
import org.tlc.whereat.ui.main.MainStyles._

trait MainLayout {

var goButton = slot[CircleView]

def layout(implicit appContext: AppContext, context: ActivityContext) = {

getUi {
l[LinearLayout](
w[CircleView] <~
wire(goButton) <~ goButtonStyle
) <~ goButtonWrapperStyle
}
}
}

custom view:

package org.tlc.whereat.ui.components

import android.content.Context
import android.graphics.Paint.Style
import android.graphics.{Canvas, Paint}
import android.util.AttributeSet
import android.view.View
import macroid.FullDsl._
import macroid.{AppContext, Snail, Tweak}

class CircleView(context: Context, attr: AttributeSet, defStyleAttr: Int)
extends View(context, attr, defStyleAttr) {

def this(context: Context) = this(context, null, 0)
def this(context: Context, attr: AttributeSet) = this(context, attr, 0)

private val paint = { val p = new Paint(); p.setStyle(Style.FILL); p}
def setColor(color: Int) = paint.setColor(color)
def getColor: Int = paint.getColor

override def onDraw(canvas: Canvas): Unit = {
super.onDraw(canvas)
canvas.drawCircle(getWidth / 2, getHeight / 2, getWidth / 2, paint)
}

}

object CircleView {
type W = CircleView

def cvColor(color: Int) = Tweak[W] (_.setColor(color))
def cvColorChange(color: Int) = Tweak[W] ({ cv ⇒ cv.invalidate(); cv.setColor(color) })
def delayedCvColorChange(color: Int, time: Int): Snail[W] = cvColorChange(color) ++ delay(time)

def toggleGoButton(on: Int, off: Int) = Tweak[W] { cv ⇒
cv.invalidate()
val next = if (cv.getColor == on) off else on
cv.setColor(next)
}
def toastSharingStatus(cv: Option[CircleView], on: Int, off: Int)(implicit appContext: AppContext) = {
val msg = if (cv.get.getColor == on) "off" else "on"
toast(s"Location sharing turned $msg.") <~ fry
}
}

--

Nick Stanchenko

unread,
Jun 14, 2015, 9:08:18 AM6/14/15
to mac...@googlegroups.com, guest....@gmail.com
Hi Austin,

Thanks for the detailed post! This is how issues should be reported, period :)
I think you might be missing an implicit scala.concurrent.ExecutionContext in scope. Could you try importing scala.concurrent.ExecutionContext.Implicits.global?
To my defense, the @implicitNotFound message does suggest that at the end of the line :)

Nick
Reply all
Reply to author
Forward
0 new messages