Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add neko.listeners.adapter-view namespace + tests
- Loading branch information
Showing
2 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
; Copyright © 2011 Sattvik Software & Technology Resources, Ltd. Co. | ||
; All rights reserved. | ||
; | ||
; This program and the accompanying materials are made available under the | ||
; terms of the Eclipse Public License v1.0 which accompanies this distribution, | ||
; and is available at <http://www.eclipse.org/legal/epl-v10.html>. | ||
; | ||
; By using this software in any fashion, you are agreeing to be bound by the | ||
; terms of this license. You must not remove this notice, or any other, from | ||
; this software. | ||
|
||
(ns neko.listeners.adapter-view | ||
"Uility functions and macros for creating listeners corresponding to the | ||
android.widget.AdapterView class." | ||
{:author "Daniel Solano Gómez"}) | ||
|
||
(defn on-item-click-call | ||
"Takes a function and yields an AdapterView.OnItemClickListener object that | ||
will invoke the function. This function must take the following four | ||
arguments: | ||
parent the AdapterView where the click happened | ||
view the view within the AdapterView that was clicked | ||
position the position of the view in the adapter | ||
id the row id of the item that was clicked" | ||
[handler-fn] | ||
{:pre [(fn? handler-fn)] | ||
:post [(instance? android.widget.AdapterView$OnItemClickListener %)]} | ||
(reify android.widget.AdapterView$OnItemClickListener | ||
(onItemClick [this parent view position id] | ||
(handler-fn parent view position id)))) | ||
|
||
(defmacro on-item-click | ||
"Takes a body of expressions and yields an AdapterView.OnItemClickListener | ||
object that will invoke the body. The body takes the following implicit | ||
arguments: | ||
parent the AdapterView where the click happened | ||
view the view within the AdapterView that was clicked | ||
position the position of the view in the adapter | ||
id the row id of the item that was clicked" | ||
[& body] | ||
`(on-item-click-call (fn [~'parent ~'view ~'position ~'id] ~@body))) | ||
|
||
(defn on-item-long-click-call | ||
"Takes a function and yields an AdapterView.OnItemLongClickListener object | ||
that will invoke the function. This function must take the following four | ||
arguments: | ||
parent the AdapterView where the click happened | ||
view the view within the AdapterView that was clicked | ||
position the position of the view in the adapter | ||
id the row id of the item that was clicked | ||
The function should evaluate to a truthy value if it has consumed the long | ||
click; otherwise false or nil." | ||
[handler-fn] | ||
{:pre [(fn? handler-fn)] | ||
:post [(instance? android.widget.AdapterView$OnItemLongClickListener %)]} | ||
(reify android.widget.AdapterView$OnItemLongClickListener | ||
(onItemLongClick [this parent view position id] | ||
(boolean (handler-fn parent view position id))))) | ||
|
||
(defmacro on-item-long-click | ||
"Takes a body of expressions and yields an | ||
AdapterView.OnItemLongClickListener object that will invoke the body. The | ||
body takes the following implicit arguments: | ||
parent the AdapterView where the click happened | ||
view the view within the AdapterView that was clicked | ||
position the position of the view in the adapter | ||
id the row id of the item that was clicked | ||
The body should evaluate to a truthy value if it has consumed the long click; | ||
otherwise false or nil." | ||
[& body] | ||
`(on-item-long-click-call (fn [~'parent ~'view ~'position ~'id] ~@body))) | ||
|
||
(defn on-item-selected-call | ||
"Takes one or two functions and yields an AdapterView.OnItemSelectedListener object | ||
that will invoke the functions. The first function will be called to handle the | ||
onItemSelected(…) method and must take the following four arguments: | ||
parent the AdapterView where the selection happened | ||
view the view within the AdapterView that was clicked | ||
position the position of the view in the adapter | ||
id the row id of the item that was selected | ||
If a second function is provided, it will be called when the selection | ||
disappears from the view. It takes a single argument, the AdapterView that | ||
now contains no selected item." | ||
([item-fn] | ||
{:pre [(fn? item-fn)] | ||
:post [(instance? android.widget.AdapterView$OnItemSelectedListener %)]} | ||
(on-item-selected-call item-fn nil)) | ||
([item-fn nothing-fn] | ||
{:pre [(fn? item-fn) | ||
(or (nil? nothing-fn) | ||
(fn? nothing-fn))] | ||
:post [(instance? android.widget.AdapterView$OnItemSelectedListener %)]} | ||
(reify android.widget.AdapterView$OnItemSelectedListener | ||
(onItemSelected [this parent view position id] | ||
(item-fn parent view position id)) | ||
(onNothingSelected [this parent] | ||
(when nothing-fn | ||
(nothing-fn parent)))))) | ||
|
||
(defmacro on-item-selected | ||
"Takes a body of expressions and yields an AdapterView.OnItemSelectedListener | ||
object that will invoke the body The body takes the following implicit | ||
arguments: | ||
type either :item corresponding an onItemSelected(…) call or :nothing | ||
corresponding to an onNothingSelected(…) call | ||
parent the AdapterView where the selection happened or now contains no | ||
selected item | ||
view the view within the AdapterView that was clicked. If type is | ||
:nothing, this will be nil | ||
position the position of the view in the adapter. If type is :nothing, this | ||
will be nil. | ||
id the row id of the item that was selected. If type is :nothing, | ||
this will be nil." | ||
[& body] | ||
`(let [handler-fn# (fn [~'type ~'parent ~'view ~'position ~'id] | ||
~@body)] | ||
(on-item-selected-call | ||
(fn ~'item-handler [parent# view# position# id#] | ||
(handler-fn# :item parent# view# position# id#)) | ||
(fn ~'nothing-handler [parent#] | ||
(handler-fn# :nothing parent# nil nil nil))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
; Copyright © 2011 Sattvik Software & Technology Resources, Ltd. Co. | ||
; All rights reserved. | ||
; | ||
; This program and the accompanying materials are made available under the | ||
; terms of the Eclipse Public License v1.0 which accompanies this distribution, | ||
; and is available at <http://www.eclipse.org/legal/epl-v10.html>. | ||
; | ||
; By using this software in any fashion, you are agreeing to be bound by the | ||
; terms of this license. You must not remove this notice, or any other, from | ||
; this software. | ||
|
||
(ns neko.listeners.adapter-view-test | ||
"Tests for the neko.listeners.adapter-view namespace." | ||
{:author "Daniel Solano Gómez"} | ||
(:gen-class :main false | ||
:extends android.test.AndroidTestCase | ||
:methods [[testOnItemClick [] void] | ||
[testOnItemLongClick [] void] | ||
[testOnItemSelected [] void]] | ||
:exposes-methods {setUp superSetUp}) | ||
(:import [android.widget ArrayAdapter ListView]) | ||
(:use neko.context | ||
neko.listeners.adapter-view | ||
junit.assert)) | ||
|
||
(def test-parent (atom nil)) | ||
(def test-adapter (atom nil)) | ||
(def test-pos 3) | ||
(def test-view (atom nil)) | ||
(def test-id (atom nil)) | ||
|
||
(defn -setUp | ||
"Creates new view for testing." | ||
[this] | ||
(.superSetUp this) | ||
(with-context (.getContext this) | ||
(reset! test-parent (ListView. *context*)) | ||
(reset! test-adapter | ||
(ArrayAdapter. *context* | ||
(get-layout :android/simple_list_item_1) | ||
(get-id :android/text1) | ||
(into-array ["One" "Two" "Three" "Four"])))) | ||
(reset! test-view (.getView @test-adapter test-pos nil nil)) | ||
(reset! test-id (.getItemId @test-adapter test-pos))) | ||
|
||
(defn -testOnItemClick | ||
"Tests the on-item-click macro and on-item-click-call macro." | ||
[this] | ||
(let [count (atom 0) | ||
fn-listener (on-item-click-call (fn [p v pos id] | ||
(when (and (= v @test-view) | ||
(= p @test-parent) | ||
(= pos test-pos) | ||
(= id @test-id)) | ||
(swap! count inc)))) | ||
macro-listener (on-item-click (when (and (= view @test-view) | ||
(= parent @test-parent) | ||
(= position test-pos) | ||
(= id @test-id)) | ||
(swap! count inc)))] | ||
(.onItemClick fn-listener @test-parent @test-view test-pos @test-id) | ||
(.onItemClick macro-listener @test-parent @test-view test-pos @test-id) | ||
(is-eq 2 @count))) | ||
|
||
(defn -testOnItemLongClick | ||
"Tests the on-item-long-click macro and on-item-long-click-call macro." | ||
[this] | ||
(let [fn-listener (on-item-long-click-call | ||
(fn [p v pos id] | ||
(if (and (= v @test-view) | ||
(= p @test-parent) | ||
(= pos test-pos) | ||
(= id @test-id)) | ||
"foo!" | ||
false))) | ||
macro-listener (on-item-long-click | ||
(if (and (= view @test-view) | ||
(= parent @test-parent) | ||
(= position test-pos) | ||
(= id @test-id)) | ||
nil | ||
true))] | ||
(is (.onItemLongClick fn-listener @test-parent @test-view test-pos | ||
@test-id)) | ||
(is-not (.onItemLongClick macro-listener @test-parent @test-view test-pos | ||
@test-id)))) | ||
|
||
(defn -testOnItemSelected | ||
"Tests the on-item-selected macro and on-item-selected-call macro." | ||
[this] | ||
(let [results (atom []) | ||
item-fn (fn [parent view pos id] | ||
(when (and (= parent @test-parent) | ||
(= view @test-view) | ||
(= pos test-pos) | ||
(= id @test-id)) | ||
(swap! results conj :item-fn))) | ||
item-listener (on-item-selected-call item-fn) | ||
both-listener (on-item-selected-call | ||
item-fn | ||
(fn [parent] | ||
(when (= parent @test-parent) | ||
(swap! results conj :nothing-fn)))) | ||
macro-listener (on-item-selected | ||
(cond | ||
(and (= type :item) | ||
(= parent @test-parent) | ||
(= view @test-view) | ||
(= position test-pos) | ||
(= id @test-id)) | ||
(swap! results conj :item-macro) | ||
(and (= type :nothing) | ||
(= parent @test-parent) | ||
(= view nil) | ||
(= position nil) | ||
(= id nil)) | ||
(swap! results conj :nothing-macro))) | ||
listeners [item-listener both-listener macro-listener]] | ||
(dorun (map #(.onItemSelected % @test-parent @test-view test-pos @test-id) | ||
listeners)) | ||
(dorun (map #(.onNothingSelected % @test-parent) | ||
listeners)) | ||
(is-eq [:item-fn :item-fn :item-macro :nothing-fn :nothing-macro] | ||
@results))) |