空うさぎのソース管理、チケット管理をBacklogに移行しました。
場所は Backlog-空うさぎ です。
guest/guestで入ればチケットが見れます。
実装予定はあんのー? とか気になった時とか、よければ見て下さい。
Twitterで #sora_usagi のハッシュ付きでつぶやいてくれても反応しますので、それでもいいんですが。
guestの権限では、残念ながらソースコードは見れないです。
オープンソースのプロジェクトでも使えるように、ログイン無しで 課題とソースコードを見れるような設定がほしー!と要望はしておいたので、今後その機能が実装されることを期待。
Backlogにはスペースという概念があって、1スペース毎の契約になります。
契約内容により、プロジェクトがいくつ作成できるかが決まります。
スペース名を「sorausagi」にしちゃったんですが、他のプロジェクトをたてることも考えたら、違う名前にした方がよかったかも。。失敗。
まぁ、他のアプリを作るときにも「空うさぎシリーズ」にしてしまったらいいのか!
空うさぎという名前、うさぎクラスタの方々の反応がとてもよいです。
名前でひっかかって試してくれた方もいるみたいー。うれしいですねー。
TwitterのTLもうさぎアイコンの方が増えていい感じ!
空うさぎのページも更新しなくっちゃなぁー。
日本語だけじゃなく、英語ページも作りたいんだけど、作りやすい良いツールないですかね?
Google Translate ToolKitみたいなUIで翻訳作業できたら便利でいいんだけどなぁー。
Google Translate Toolkit の メニュー>共有に「ソース ページに公開」ってあるんだけど、これを自分のページへの設定ができたらいいのになぁ。。
2010年2月7日日曜日
空うさぎのBTSをBacklogに移行しました
AdobeAIRで常駐アプリを作る
FriendFeed,Twitter,RSSのクライアントとして作成中の空うさぎですが、どこから皆さん見つけてきているのかが分からないのですが、新しいバージョンのダウンロード数が336件になりましたー。
有り難うございまっす。
んで、前から要望のあった常駐化対応をやっている最中です。
やりたい動きとしては
- メイン画面を閉じてもアプリは終了せず常駐する
- Windowsの場合はタスクトレイ、Macの場合はDocを表示し、アイコンをクリックしたらメイン画面を復帰
メイン画面を閉じてもアプリは終了せず常駐する
画面の×ボタンを押されたタイミングで画面のvisibleをfalseにすればよさそう。
mx:WindowedApplication の closingのタイミングで以下のコードを書く。
/* WindowをCloseするタイミングでの処理 */
public function onWindowClosing(e:Event):void {
visible = false;
e.preventDefault();
}
closingのタイミングであれば、処理をキャンセルすることができるので、e.preventDefault(); で画面終了処理をキャンセルしてます。
Windowsの場合はタスクトレイ、Macの場合はDocを表示し、アイコンをクリックしたらメイン画面を復帰
if (NativeApplication.supportsMenu) {
// Mac用のDocを作成する処理
} else {
// Windows用のタスクトレイを作成する処理
}
でまずは処理を切替。
/* DocIconの設定 */
private function setDockIcon(menu:NativeMenu):void {
var doc:DockIcon = NativeApplication.nativeApplication.icon as DockIcon;
doc.bitmaps = [new icon128x128()];
doc.menu = menu;
NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, systemTrayIconClickHandler);
}
/* SystemTrayの設定 */
private function setSystemTrayIcon(menu:NativeMenu):void {
var tray:SystemTrayIcon = NativeApplication.nativeApplication.icon as SystemTrayIcon;
tray.bitmaps = [new icon32x32(), new icon16x16()];
tray.menu = menu;
tray.tooltip = applicationName;
tray.addEventListener(MouseEvent.CLICK, systemTrayIconClickHandler);
}
/* タスクトレイ、Docをクリックした時の処理 */
private function systemTrayIconClickHandler(event:Event) :void {
if (!mainWindow.visible || mainWindow.nativeWindow.displayState == NativeWindowDisplayState.MINIMIZED) {
if (!mainWindow.nativeWindow.visible) {
mainWindow.nativeWindow.visible = true;
}
mainWindow.nativeWindow.restore();
mainWindow.activate();
mainWindow.setFocus();
}
}
で、Docとシステムトレイを作成します。
クリックのタイミングを拾うには、Windowsではタスクトレイに対して addEventListener(MouseEvent.CLICK, handler); をすれば拾えるっぽいのですが、MacのDocは拾えないみたい。
Docの場合は、マウスをクリックすると、NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, handler); が呼ばれるようなので、これで対応。
これで今の所、動いている感じ。。
2010年2月1日月曜日
Flexで重複チェックする
FlexでのチェックはValidatorを使えます。
このサブクラスとして既に実装されているValidatorは
CreditCardValidator, CurrencyValidator, DateValidator, EmailValidator, NumberValidator, PhoneNumberValidator, RegExpValidator, SocialSecurityValidator, StringValidator, ZipCodeValidator があります。
これ以外のValidatorって自作する場合、どう作るんだろう? と思い作成してみました。
今回欲しかったのは、重複チェックのValidator。
複数のObjectを登録できるが、名前は重複させたくない という場合の時に使うためのものです。
- ArrayCollectionの中にAオブジェクトが複数入っている。
- Aオブジェクトには name という属性がある。
- 新規追加する時は、ArrayCollectionの中に同じnameが入っていたらエラー。
- 更新する時には、更新対象オブジェクト以外でチェックする。(excludeの設定)
- 必須入力の項目でもある
という前提だと、
var validator:Validator = new DuplicateValidator(arrayCollection, "name", excludeObject);
validator.source = txtName;
validator.property = "text";
validator.required = true;
ように設定するものになります。
/**
* リストの中に重複がないかチェックする
* @author ogawa
*/
package org.sorausagi.air.ui.setting.rss {
import mx.validators.Validator;
import mx.validators.ValidationResult;
import mx.collections.ArrayCollection;
public class DuplicateValidator extends Validator {
/* 元々のリスト */
private var list:ArrayCollection;
/* リスト内オブジェクトの名前 */
private var listName:String;
/* 除外するオブジェクト */
private var excludeObject:Object;
/* このValidatorのErrorMessage */
private var _fieldError:String = "既に使われている名前です";
public function DuplicateValidator(list:ArrayCollection, listName:String, excludeObject:Object = null) {
this.list = list;
this.listName = listName;
this.excludeObject = excludeObject;
}
public function set fieldError(message:String):void {
this._fieldError = fieldError;
}
public function get fieldError():String {
return _fieldError;
}
override protected function doValidation(value:Object):Array {
var results:Array = super.doValidation(value);
var val:String = value ? String(value) : "";
if (results.length < 0 || ((val.length == 0) && !required)) {
return results;
}
return validateDuplicate(this, value, null);
}
public function validateDuplicate(validator:Validator, value:Object, baseField:String):Array {
var results:Array = [];
for each (var item:Object in list) {
if (excludeObject != null && excludeObject == item) {
continue;
}
if (item[listName] == value) {
results.push(new ValidationResult(
true, "","deplicated",
fieldError));
break;
}
}
return results;
}
}
}
使ってみた画面はこんな感じ。
2010年1月24日日曜日
SuperTable内のラジオボタンの選択が有効にならない
HTMLでテーブルのスクロールを実現したいため、SuperTableというのを使ってみました。
SuperTableは縦スクロール、横スクロールも実現できます。
ですが、RadioButtonを入れると、選択表示にならないという状態になる。HTMLのinputにはcheckedついているのに!
その原因は、スクロールテーブルの実現方法にあるんですが、SuperTableのスタイルシートを外すと見えてきます。
まず、fixedCol:0 = 列固定を無し に指定してみると、こんな感じになります。
行ヘッダーの列を2つにして、cssで縦スクロールを実現しているんですね。
次に、fixedCol:1 = 1つ目の列を固定 に指定してみると、こんな感じになります。
テーブル内のラジオボタンの行までガシガシ作られちゃってます。
ラジオボタンはグループ内で1つのみの選択という作りをしますので、複製された行は未選択状態になります。
この状態でSuperTableのcssをあてると、綺麗に全部未選択状態に見えてしまいます。
そこで、複製された方の列のラジオをJavaScriptで無理矢理選択状態にしてみる
try {
var myST = new superTable("matrixb41dbb", {
cssSkin : "sDefault",
headerRows : 0,
fixedCols : 1,
colWidths : [150,100,100,100]
});
} catch (e) { }
checkRadio(document.form1.test1, "あ");
checkRadio(document.form1.test2, "い");
checkRadio(document.form1.test3, "う");
checkRadio(document.form1.test4, "あ");
checkRadio(document.form1.test5, "い");
checkRadio(document.form1.test6, "う");
function checkRadio(radios, selected) {
for (i=radios.length - 1; i>=0;i--){
if (radios[i].value===selected) {
radios[i].checked = true;
break;
}
}
}
すると、上手く表示されるようになります。
この状態で、fixedCols : 2 = 2列目まで列固定 にして試してみると、2列目のラジオの選択が見えなくなってしまいます。

つまり、列固定している列は1つめのテーブルの情報を、列固定していない列は2つ目のテーブルの情報を見てるよーです。
なので、今回の例では2列目の「あ」の選択値の場合は、1つ目のテーブルのラジオを選択してあげれば見れるようになります。
checkRadioFirst(document.form1.test1, "あ");
checkRadio(document.form1.test2, "い");
checkRadio(document.form1.test3, "う");
checkRadioFirst(document.form1.test4, "あ");
checkRadio(document.form1.test5, "い");
checkRadio(document.form1.test6, "う");
function checkRadioFirst(radios, selected) {
for (i=0; i<radios.length - 1;i++){
if (radios[i].value===selected) {
radios[i].checked = true;
break;
}
}
}
cssを当てない状態ではこんな感じに仕上げる。

たまたま、ラジオで選択が表示されなくなって気づきましたが、textやcheckboxも2重に生成されることになります。
なので、HTMLで情報送信したがサーバで上手く反映されない...とハマるパターンもありそう。
なんにも考えずに使うと怖いなーと思った一件でした。
2010年1月22日金曜日
HTMLを後でiPhoneで見る
前回のエントリで、
Web上でチェックした項目を、iPhoneでさっと見れるようなアプリもあったらいいな。
と書いたのですが、ReadItLater,Instapaperというサービスを教えてもらいました。
両方とも、URLをサービスに送信して登録できて、iPhoneアプリからそのHTMLを見る事ができます。もちろん、Webからでも。
これで、気になった記事をバシバシとうろくして、喫煙所でゆっくりと見れる!
iPhoneのUIはReadItLaterの方が好きなので、こっちをメインにしてみようかなぁー
なかなか便利なので、空うさぎにReadItLater、InstapaperにURLを登録する機能をつけてみようかと考え中です。
それとともに、短縮URLの元URLと、HTMLタイトルを取ってくるようにしてリンクのリストを作ろうかと。
元URLはHEADでリクエストを投げて、Locationが入っていたらその値を元エントリとしてます。
var req : URLRequest = new URLRequest(url);
req.method = URLRequestMethod.HEAD;
req.followRedirects = false;
var loader:URLLoader = new URLLoader();
var expandUrl:String;
function onResult(event:HTTPStatusEvent):void {
for each(var rh : URLRequestHeader in event.responseHeaders) {
if (rh.name == "Location") {
expandUrl = rh.value;
return;
}
}
}
loader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, onResult);
loader.load(req);
HTMLのタイトルは、単純にHTMLを取得して、<title>のタグの値を取得してます。
ここの所は@kisさんにサンプルコードを頂きました。
@aqubi 使い物にならないものならこちらで! http://d.hatena.ne.jp/nowokay/20100121
文字コードが問題になるので、HTMLヘッダのContent-Typeにcharsetが入っていたら、その文字コードで判断してるんですが、結構charsetが入っていないサイトが多いんですね。。
この部分のActionScript3は、
var req : URLRequest = new URLRequest(expandUrl);
req.method = URLRequestMethod.GET;
_loader = new URLLoader();
_loader.dataFormat = URLLoaderDataFormat.BINARY;
_loader.addEventListener(Event.COMPLETE, onResult);
_loader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, httpResponse);
_loader.load(req);
という感じで、dataFormatをURLLoaderDataFormat.BINARYにしてバイナリでまず取得。
HTTPStatusEventでresponseHeadersの中から、Content-Typeを引っこ抜いて、charsetをとる。
protected function onResult(event:Event):void {
var bytes:ByteArray = _loader.data as ByteArray;
var content:String = ba.readMultiByte(bytes.length, charset);
}
結果をreadMultiByteで変換してStringを作成。
んで、titleを取ってくる感じ。
charsetが入っていない場合でも、utf-8であるものも結構多い気がするのでとれなかったらutf-8にして文字化けしたらごめんなさいね。。。って感じかなぁー。うーむ。
ちなみに、AIRには、flash.html.HTMLLoaderというLoaderもあって、これを使うとHTMLをレンダリングしてくれる状態まで情報を取得/用意してくれます。
ここから取得できる、HTMLHistoryItemというオブジェクトには、リダイレクト前のURL、リダイレクト後のURL、HTMLのタイトルが取得できるようになっているんで、今回必要な情報はばっちりとれちゃいます。んが、悪意あるHTMLだったときにどんな事になるか分かんないので怖くて使ってません。
ということで、現在つくっている空うさぎではこんな感じの画面がでるようになっています。

ここまでやると、ペーストした値がURLだったら、短縮URLに変換するとかしてみたいなぁ。とも考え中。
2010年1月9日土曜日
今年作成するアプリ
年始め恒例の社員総会のためヌーラボ本社@福岡に行ってきました。
昨年に引越をした本社はとっても綺麗&広くて良かったです。
初めて本格的な水炊きを食べたのですが、これが美味しくて感動!
誤解してたんですが、水炊きって鍋とは違うんですね。今までは、鶏肉が入った鍋の事を水炊きって言うんだと思ってた。
福岡の皆様、色々お世話になりました!
さてさて、社員総会では各自今年の目標を短冊に記入するのですが、私の今年の目標は「iPhoneアプリを作る」にしてみました。
ここ2年間、ずっとAdobeAIRでアプリ作っていたのでそれ以外のものをやりたい。
Objective-Cは触った事がないのもあるし。
問題はどんなアプリを作るか...ですが、ちょっと悩み中。
タイムトラッキングのアプリもいいな。
ASlimTimerっていうSlimTimerのAdobeAIRクライアントを作ってはいるのですが、開始とか停止とか忘れちゃう事があるんですよね。会議が始まる!とバタバタ移動してしまった時とか。モバイル端末だったら持ち歩いているので気づいた時に操作できるからいいかも?
Web上でチェックした項目を、iPhoneでさっと見れるようなアプリもあったらいいな。
使う場面なんですが、PC上で一通り読みたいWEBページがあった時、それをさっとiPhoneで見れるようにしてから、iPhone共々喫煙コーナーに移動して読む って事ができたらいいなーと思って。
どんな仕組でするのかはまだ考えてないけども。
あと...iPhoneアプリではなくなってしまうかと思うのですが、(オレオレ)ブックマーク/スクラップのアプリも欲しい。
ブックマークってdeliciousとか、ブラウザのものとか使ったりするんですが、後で見るブックマークって、よく知っているページがほとんど。あのサイトはブックマークしたって覚えているようなもの。
そうでないものは、結局またGoogleで検索した方が見つけるのが早かったりして。
なんかの探し物している時は特に、"ここは関連しそうな気がする "と思ったものはタブで残しつつ、新たな検索結果のページもどんどん見ていくので、大量なタブで大変になったりすることが結構あります。
といって、そういうモノはブックマークに登録しても、なんて名前のサイトだったかとか覚えてない とか、なんの情報が気になったから登録したおかも覚えてない とか、そもそも登録した事すら忘れてしまう ので、すぐには登録しない。
中には、掲示板の中に書いてある一部分のコードだけがきになっただけ...とかもあるしね。
でも、そういう検索結果は、残さずに消しちゃうのももったいないし、ブラウザが突然落ちたらどうしよう...とドキドキして使ってたりする時も多いので、なんとかしたいと思うんですよ。
よくあるブックマークの情報って、
URLがメインの情報で、tagで簡単な補足情報(カテゴリ)を入れる感じが多いと思うのですが、その逆で、
一部の引用文章/画像 がメインで、URLが補足情報 トントンと登録しやすいものがあったら、調べ中のものをガシガシ記録として残していきやすくならないかなぁーと思うんですが、どうでしょうかね。
これの場合だったら、HTML5を使って色々できたりするかも?!
どちらにしろ、自分にとって何かしら楽になるツール を作りたいですね。
個人的に作るアプリって、自分の生活の中で楽できるものってのが、やっぱ頑張れるので。(私だけ?)
ま、最初は欲張らずに簡単なものを作りつつ温めていきたいですねw
2010年1月1日金曜日
2010年始まりました
明けましておめでとうございます。始まりました、2010年。
ということで、昨年をちょっと振り返りエントリ。
春 転職。新しい職場が渋谷なため、若者の勢いに少し圧倒され気味。
夏 AIR GEARにコード補完機能を追加。このコード補完は欲しいー!機能ですがなかなか難しくて、現在もまだ中途半端な状態。
もう少し手を入れねば..と現在も良い方法を思案中。
秋 ASlimTimerにGrowl風の通知ウィンドウを追加。
これが出来るなら、FriendFeedのクライアントもできるんじゃないかなぁ?と思い、AFriendFeed(現在は空うさぎ)を作成開始。
これがきっかけとなった問題発言(笑)
冬 業務でDocomo,Softbank携帯 , Blackberry のアプリ開発をしてた。携帯の開発って難しいなぁ...と思う。
何が難しいって、エミュレータと実機とで状況が変わってしまう とか、Unitテストがしにくい とか、提供されているライブラリのソースが公開されていない とかで。
あと、エミュレータを動かすEclipseプラグインにちょっとイラつくw
残念ながら、Android/iPhoneはやってなかったのですが、やっぱこれからはAndroidかなぁーなんて。
やっぱり、一般開発者に開発しやすい環境を提供するのは大事ですよー。
企業単位で囲い込みじゃなくて、個々の開発者単位のファンを増やす環境=オープンな環境 ってのは大事だよなーと思う。
FriendFeedクライアントとして作り始めた空うさぎは、FriendFeedユーザでないTwitterのフォローアーの状況も一気に取り込みたい...欲求からTwitterのAPIを使ってTwitter情報もどんどん取り込みしてしまった。
結局、自分が使いやすいFrinedFeed+Twitterクライアントになっていく。。
後半を振り返ると、夜な夜な空うさぎをメンテしている日々で、AIR GEARもなかなか触れず。
Twitter/FriendFeedは日々使うツールだからあれも、これも...と色々欲しくなってくるからですねー。
作り始めて半年ぐらいですが感じることとしては、"気に入るTwitter/FriendFeedクライアントがないのであれば作ってしまえばいい"
TLの量/内容/チェックしたい内容の量/家なのか、会社なのか などなどにより、見る方法、チェックしたい内容 がかわってきます。
だから、誰にとっても完璧なクライアントって作れないんじゃないかと。(まぁ、発想の転換でできるんかもしれないけど)
Twitter クライアント作者ミーティングに参加させて思ったんですが、たとえ新たなクライアントを作ったとしても、既に作っている人にとっての敵になるわけじゃーない。
気軽に作ってみて、こんな新たなUI/機能 はあると良くない? というのを世の中に伝えるだけでも凄くいいと思う。
(企業で作ってるのであれば、敵になるんかもしれませんが)
作るのは面倒だしちょっと...というのであれば、
"いいクライアントがないー"
"このクライアントはいまいち..." とつぶやくぐらいなら、
"こんなクライアントないかなぁー? "
"こんな機能があると嬉しい!"
という前向きな事をつぶやいて、世の中のクライアント作者のよいヒントになるようにすればいいと思う。
そうして、いろんな人が知恵をしぼり合って、今後もよいクライアントがどんどん増えていけばいいなぁーと思います。
もちろん、空うさぎも、おー!これはいい! と思う機能を発見しつつポチポチ機能を増やしていきたいな。と思うし、他のクライアント作者へよいヒントにもなったら嬉しいな。と思う。
...と、昨年はこんな感じでしたが、今年はまた違うものを作ってみたいなぁ と思ってます。
いろんな面白そうな技術やインフラがどんどん出てくる世の中なので、凄く迷いますよねー! 楽しい世の中だ。体が複数欲しい。
