株式会社ライブキャストロゴ 株式会社ライブキャスト

flashcast:フリーで働くITエンジニア集団のブログ: google翻訳APIを使ったAIRアプリを作る!(Twitterに投稿編)の続きです。

前回、翻訳結果をtwitterに投稿する部分を実装しました。いろいろテストしているうちに、クリップボードを監視する部分に問題があることがわかりました。

今の仕様では、クリップボードの中身に変化がないと、アイコンが回転しません。アイコンが回転しないと翻訳ができないため、2回連続で同じ文字をコピーした際には、アイコンが回転せず、翻訳ができないのです。

これはよろしくない。

ということで、以下のような仕様に変更することにしました。

  1. クリップボードの監視をやめる。
  2. アイコンをクリックした時に、クリップボードの文字列を翻訳する。
  3. 翻訳後には、(とりあえず)10秒間アイコンを回転させ、回転中のアイコンをクリックされたらtwitterに翻訳結果を投稿する。
  4. 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");

こうすることで、翻訳結果が正常だったときのみ、アイコンを回転させるようにできます。

実行時のデバックトレースです。つぶやいた翻訳結果を出力しています。

console

※ 3回つぶやいてますが、twitterには1回しか投稿されませんでした。連続した同じつぶやきは無視するというtwitterの仕様だと思います。

これでクリップボードを常時Timerで監視する必要なくなったため、アプリも軽くなり、ロジックもシンプルになりました!

サンプルソース

サンプルソースをダウンロードできるようにしておきます。