diff options
author | Toshiaki Asai <toshi.alternative@gmail.com> | 2016-09-11 14:51:19 +0900 |
---|---|---|
committer | Toshiaki Asai <toshi.alternative@gmail.com> | 2016-10-03 00:19:03 +0900 |
commit | 6afa8504da7a0c520760cc9721f7b0bf36ca76e8 (patch) | |
tree | f112159c5f2871845eb93dfbf1e44055ab7f46f0 | |
parent | a4c8a984acbc38f8be9ad37f7b47c58387c6f06e (diff) | |
download | mikutter-6afa8504da7a0c520760cc9721f7b0bf36ca76e8.tar.gz |
Intentプラグイン追加 refs #866
Modelを開くためのopenイベント
Modelを開く方法を宣言するintentメソッド
-rw-r--r-- | core/lib/retriever/model.rb | 4 | ||||
-rw-r--r-- | core/plugin/intent/.mikutter.yml | 11 | ||||
-rw-r--r-- | core/plugin/intent/intent.rb | 96 | ||||
-rw-r--r-- | core/plugin/intent/model/intent.rb | 8 | ||||
-rw-r--r-- | core/plugin/intent/model/intent_token.rb | 20 | ||||
-rw-r--r-- | core/plugin/message_detail_view/.mikutter.yml | 12 | ||||
-rw-r--r-- | core/plugin/message_detail_view/message_detail_view.rb | 10 | ||||
-rw-r--r-- | core/plugin/user_detail_view/.mikutter.yml | 1 | ||||
-rw-r--r-- | core/plugin/user_detail_view/user_detail_view.rb | 11 |
9 files changed, 167 insertions, 6 deletions
diff --git a/core/lib/retriever/model.rb b/core/lib/retriever/model.rb index 9b8ba1e5..5e9541c2 100644 --- a/core/lib/retriever/model.rb +++ b/core/lib/retriever/model.rb @@ -165,11 +165,11 @@ class Retriever::Model # ==== Return # self def handle(condition) - model = self + model_slug = self.slug plugin do filter_model_of_uri do |uri, models| if condition === uri - models << model + models << model_slug end [uri, models] end diff --git a/core/plugin/intent/.mikutter.yml b/core/plugin/intent/.mikutter.yml new file mode 100644 index 00000000..250496fd --- /dev/null +++ b/core/plugin/intent/.mikutter.yml @@ -0,0 +1,11 @@ +--- +slug: :intent +depends: + mikutter: "3.5" + plugin: [] +version: '1.0' +author: toshi_a +name: intent +description: >- + ModelをUI上で開く機能を提供する。 + Pluginが特定のModelを扱えることを表明するintent DSLメソッドを提供する。 diff --git a/core/plugin/intent/intent.rb b/core/plugin/intent/intent.rb new file mode 100644 index 00000000..eec24b2a --- /dev/null +++ b/core/plugin/intent/intent.rb @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +require_relative 'model/intent' +require_relative 'model/intent_token' + +Plugin.create(:intent) do + # _uri_ を開くことができる Model を列挙するためのフィルタ + defevent :model_of_uri, + prototype: [URI, :<<] + + # _model_slug_ を開くことができる Intent を列挙するためのフィルタ + defevent :intent_select_by_model_slug, + prototype: [Symbol, :<<] + + # _model_ を開く方法を新しく登録する。 + # ==== Args + # [model] サポートするModelのClass + # [label:] + # 開き方を説明する文字列。 + # あるModelを開く手段が複数ある場合、ユーザは _label_ の内容とともに、どうやって開くか選択することになる。 + # 省略した場合はpluginの名前になる + # [slug:] + # このintentのslug。他のintentと重複してはならない。 + # 通常は指定しなくてもユニークなslugが割り当てられるが、同じ _model_ に二つ以上のintentを登録する場合は、同じslugが自動生成されてしまうので、ユニークな値を設定しなければならない。 + # 省略した場合はPluginとModelから自動生成される + # [&proc] + # パーマリンクを開く時に、 Plugin::Intent::IntentToken を引数に呼ばれる。 + # ==== Return + # self + defdsl :intent do |model, label: nil, slug: :"#{self.spec[:slug]}_#{model.slug}", &proc| + label ||= (self.spec[:name] || self.spec[:slug]) + my_intent = Plugin::Intent::Intent.new(slug: slug, label: label) + filter_intent_select_by_model_slug do |target_model_slug, intents| + if model.slug == target_model_slug + intents << my_intent + end + [target_model_slug, intents] + end + add_event(:"intent_open_#{slug}", &proc) + self + end + + on_open do |object| + case object + when Plugin::Intent::IntentToken + Plugin.call("intent_open_#{object.intent.slug}", object) + when Retriever::Model + open_model(object) + when String, URI + open_uri(object.is_a?(URI) ? object : URI.parse(object)) + end + end + + # _uri_ をUI上で開く。 + # このメソッドが呼ばれたらIntentTokenを生成して、開くことを試みる。 + # open_modelのほうが高速なので、modelオブジェクトが存在するならばopen_modelを呼ぶこと。 + # ==== Args + # [uri] 対象となるURI + def open_uri(uri) + model_slugs = Plugin.filtering(:model_of_uri, uri.freeze, Set.new).last + if model_slugs.empty? + error "model not found to open for #{uri}" + return + end + intents = model_slugs.inject(Set.new) do |memo, model_slug| + memo.merge(Plugin.filtering(:intent_select_by_model_slug, model_slug, Set.new).last) + end + if intents.empty? + error "intent not found to open for #{model_slugs.to_a}" + return + end + # TODO: intents をユーザに選択させる + intent = intents.to_a.first + Plugin::Intent::IntentToken.open( + uri: uri, + intent: intent, + parent: nil) + end + + # _model_ をUI上で開く。 + # このメソッドが呼ばれたらIntentTokenを生成して、開くことを試みる。 + # open_uriは、Modelが必要になった時にURIからModelの取得生成を試みるが、 + # このメソッドはヒントとして _model_ を与えるため、探索が発生せず高速に処理できる。 + # ==== Args + # [model] 対象となるRetriever::Model + def open_model(model) + intents = Plugin.filtering(:intent_select_by_model_slug, model.class.slug, Set.new).last + # TODO: intents をユーザに選択させる + intent = intents.to_a.first + Plugin::Intent::IntentToken.open( + uri: model.uri, + model: model, + intent: intent, + parent: nil) + end + +end diff --git a/core/plugin/intent/model/intent.rb b/core/plugin/intent/model/intent.rb new file mode 100644 index 00000000..adac53e4 --- /dev/null +++ b/core/plugin/intent/model/intent.rb @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +module Plugin::Intent + class Intent < Retriever::Model + field.string :slug, required: true + field.string :label, required: true + end +end diff --git a/core/plugin/intent/model/intent_token.rb b/core/plugin/intent/model/intent_token.rb new file mode 100644 index 00000000..e2c6b5f8 --- /dev/null +++ b/core/plugin/intent/model/intent_token.rb @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +module Plugin::Intent + class IntentToken < Retriever::Model + field.string :uri, required: true + field.has :model, Retriever::Model + field.has :intent, Plugin::Intent::Intent, required: true + + # 引数の情報からIntentTokenを作成し、それを開く + def self.open(*args) + self.new(*args).open + end + + # 設定された情報を使ってURI又はModelを開く + def open + Plugin.call(:open, self) + self + end + end +end diff --git a/core/plugin/message_detail_view/.mikutter.yml b/core/plugin/message_detail_view/.mikutter.yml new file mode 100644 index 00000000..8ee522e4 --- /dev/null +++ b/core/plugin/message_detail_view/.mikutter.yml @@ -0,0 +1,12 @@ +--- +slug: :message_detail_view +depends: + mikutter: "3.5" + plugin: + - gui + - gtk + - intent +version: '1.0' +author: toshi_a +name: ツイート詳細 +description: 単一のツイートの詳細な内容を表示するタブを追加する diff --git a/core/plugin/message_detail_view/message_detail_view.rb b/core/plugin/message_detail_view/message_detail_view.rb index f931ec3c..cad6e296 100644 --- a/core/plugin/message_detail_view/message_detail_view.rb +++ b/core/plugin/message_detail_view/message_detail_view.rb @@ -2,16 +2,22 @@ miquire :mui, 'retriever_header_widget' Plugin.create(:message_detail_view) do + intent Message, label: _('ツイートの詳細') do |intent_token| + show_message(intent_token.model) + end + command(:message_detail_view_show, name: '詳細', condition: lambda{ |opt| opt.messages.size == 1 && opt.messages.first.is_a?(Message) }, visible: true, role: :timeline) do |opt| - Plugin.call(:show_message, opt.messages.first) + Plugin.call(:open, opt.messages.first) end + # 互換性のため。 + # openイベントを使おう on_show_message do |message| - show_message(message) + Plugin.call(:open, message) end def show_message(message, force=false) diff --git a/core/plugin/user_detail_view/.mikutter.yml b/core/plugin/user_detail_view/.mikutter.yml index 13e75ab0..e1d0e614 100644 --- a/core/plugin/user_detail_view/.mikutter.yml +++ b/core/plugin/user_detail_view/.mikutter.yml @@ -7,6 +7,7 @@ depends: - gtk - command - uitranslator + - intent version: '1.0' author: toshi_a name: プロフィール diff --git a/core/plugin/user_detail_view/user_detail_view.rb b/core/plugin/user_detail_view/user_detail_view.rb index 58cde808..a4dcd291 100644 --- a/core/plugin/user_detail_view/user_detail_view.rb +++ b/core/plugin/user_detail_view/user_detail_view.rb @@ -4,6 +4,11 @@ Plugin.create :user_detail_view do UserConfig[:profile_show_tweet_once] ||= 20 UserConfig[:profile_icon_size] ||= 64 UserConfig[:profile_icon_margin] ||= 8 + + intent User, label: _('プロフィール') do |intent_token| + show_profile(intent_token.model) + end + plugin = self def timeline_storage # {slug: user} @timeline_storage ||= {} end @@ -30,8 +35,10 @@ Plugin.create :user_detail_view do else [messages] end end + # 互換性のため。 + # openイベントを使おう on_show_profile do |service, user| - show_profile(user) end + Plugin.call(:open, user) end def show_profile(user, force=false) slug = "profile-#{user.uri}".to_sym @@ -133,7 +140,7 @@ Plugin.create :user_detail_view do visible: true, icon: lambda{ |opt| opt && opt.messages.first.user[:profile_image_url] }, role: :timeline) do |opt| - Plugin.call(:show_profile, Service.primary, opt.messages.first.user) end + Plugin.call(:open, opt.messages.first.user) end def mutebutton(user) changer = lambda{ |new, widget| |