flashcast:フリーで働くITエンジニア集団のブログ: google翻訳APIを使ったAIRアプリを作る!(Twitterに投稿編)の続きです。
前回、翻訳結果をtwitterに投稿する部分を実装しました。いろいろテストしているうちに、クリップボードを監視する部分に問題があることがわかりました。
今の仕様では、クリップボードの中身に変化がないと、アイコンが回転しません。アイコンが回転しないと翻訳ができないため、2回連続で同じ文字をコピーした際には、アイコンが回転せず、翻訳ができないのです。
これはよろしくない。
ということで、以下のような仕様に変更することにしました。
- クリップボードの監視をやめる。
- アイコンをクリックした時に、クリップボードの文字列を翻訳する。
- 翻訳後には、(とりあえず)10秒間アイコンを回転させ、回転中のアイコンをクリックされたらtwitterに翻訳結果を投稿する。
- 10秒間、クリックされなければ回転を止める。
こうすることで、前回課題として残った、
twitterに翻訳結果を投稿しないと、次の翻訳はできないので不便です。その点は、今後、改善していきたいと思います。
の点も、改善できると思います。
まず、1.の仕様変更により、クリップボードを監視するクラスは不要になりました。それにともない、そのインスタンスも不要になります。
続いて、2.の部分の、アイコンをクリックされた時のロジックを追加します。46行目になります。
package { // ~ 省略 ~ public class IconManager extends EventDispatcher { // ~ 省略 ~ private var isAnimate:Boolean = false; private var isSecond:Boolean = false; private var isDecrement:Boolean = false; private var isReverse:Boolean = false; private var _gmodel:TranslateModel; private var _timer:Timer; public function IconManager():void { } public function initIconManager(gmodel:TranslateModel):void { _gmodel = gmodel; _timer = new Timer(10000); _timer.addEventListener(TimerEvent.TIMER, onTimerHandler); initIcon(); } // ~ 省略 ~ private function onIconClick(event:Event):void { if (isSecond) { if (isAnimate) { if (NativeApplication.supportsSystemTrayIcon) { setIcon(newIconBitmap); } isAnimate = false; } else { if (!Clipboard.generalClipboard.hasFormat(ClipboardFormats.TEXT_FORMAT)) { return; } _gmodel.Original = Clipboard.generalClipboard.getData(ClipboardFormats.TEXT_FORMAT) as String; } dispatchEvent(new TranslatorSampleEvent(TranslatorSampleEvent.ICON_CLICK)); } else { isSecond = true; } } // ~ 省略 ~ private function onTimerHandler(event:TimerEvent):void { isAnimate = false; if (NativeApplication.supportsSystemTrayIcon) { setIcon(newIconBitmap); } dispatchEvent(new TranslatorSampleEvent(TranslatorSampleEvent.ICON_TIMER)); } public function timerStart():void { _timer.start(); } public function timerStop():void { _timer.stop(); } } }
ここでは、アイコンをクリックされた時に、クリップボードの中身を取得するようにしています。また、仕様変更4.の10秒間、クリックされなければ回転を止める部分は、Timerクラスを使って実装しています。
メインのロジックは、以下のようになります。
package { import flash.events.Event; import mx.binding.utils.ChangeWatcher; import mx.core.Application; import mx.events.PropertyChangeEvent; public class TranslatorSample7Base extends Application { private var imanager:IconManager; private var gmanager:TranslateManager; private var tmanager:TwitterManager; private var gmodel:TranslateModel; private var tweet:Boolean; public function TranslatorSample7Base():void { } public function initApp():void { gmodel = new TranslateModel(); imanager = new IconManager(); gmanager = new TranslateManager(); tmanager = new TwitterManager(); imanager.initIconManager(gmodel); gmanager.initTranslateManager(gmodel); tmanager.initTwitterManager(); ChangeWatcher.watch(gmodel, '_result', onResultChangeHandler); imanager.addEventListener(TranslatorSampleEvent.ICON_CLICK, onIconClick); imanager.addEventListener(TranslatorSampleEvent.ICON_TIMER, onIconTimerHandler); } private function onIconClick(event:TranslatorSampleEvent):void { if (tweet) { this.removeEventListener(Event.ENTER_FRAME, imanager.iconAnimate); imanager.timerStop(); tmanager.Tweet(gmodel.Translated.substr(0, 140)); tweet = false; } else { gmodel.Result = false; gmanager.Translate("1.0", gmodel.Original, "en", "ja"); } } private function onResultChangeHandler(event:PropertyChangeEvent):void { if (event.newValue as Boolean) { this.addEventListener(Event.ENTER_FRAME, imanager.iconAnimate); imanager.timerStart(); tweet = true; } } private function onIconTimerHandler(event:TranslatorSampleEvent):void { this.removeEventListener(Event.ENTER_FRAME, imanager.iconAnimate); imanager.timerStop(); tweet = false; } } }
仕様変更3.の翻訳後に、(とりあえず)10秒間アイコンを回転させる部分は、前回まで、
ChangeWatcher.watch(gmodel, '_translated', onTranslatedChangeHandler);
のように、「翻訳結果」の変化をウォッチするようにしていました。今回の仕様変更で、翻訳結果にも変化がないケースも発生するようになるので、新たにModelクラスに「翻訳処理の実行結果(正常終了/異常終了)」を格納するためのメンバーを追加し、それをウォッチするようにしました。
ChangeWatcher.watch(gmodel, '_result', onResultChangeHandler);
メンバーを追加したModelクラスです。
package { [Bindable] public class TranslateModel { public var _original:String; private var _translated:String; public var _result:Boolean; public function TranslateModel() { } public function set Original(original:String):void { _original = original; } public function get Original():String { return _original; } public function set Translated(translated:String):void { _translated = translated; } public function get Translated():String { return _translated; } public function set Result(result:Boolean):void { _result = result; } public function get Result():Boolean { return _result; } } }
翻訳実行後に、正常終了したら変化が起こるよう、翻訳直前に、このメンバーを初期化しています。
gmodel.Result = false; gmanager.Translate("1.0", gmodel.Original, "en", "ja");
こうすることで、翻訳結果が正常だったときのみ、アイコンを回転させるようにできます。
実行時のデバックトレースです。つぶやいた翻訳結果を出力しています。
※ 3回つぶやいてますが、twitterには1回しか投稿されませんでした。連続した同じつぶやきは無視するというtwitterの仕様だと思います。
これでクリップボードを常時Timerで監視する必要なくなったため、アプリも軽くなり、ロジックもシンプルになりました!
サンプルソース
サンプルソースをダウンロードできるようにしておきます。
- TranslatorSample7:ダウンロード