aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToshiaki Asai <toshi.alternative@gmail.com>2016-09-11 14:51:19 +0900
committerToshiaki Asai <toshi.alternative@gmail.com>2016-10-03 00:19:03 +0900
commit6afa8504da7a0c520760cc9721f7b0bf36ca76e8 (patch)
treef112159c5f2871845eb93dfbf1e44055ab7f46f0
parenta4c8a984acbc38f8be9ad37f7b47c58387c6f06e (diff)
downloadmikutter-6afa8504da7a0c520760cc9721f7b0bf36ca76e8.tar.gz
Intentプラグイン追加 refs #866
Modelを開くためのopenイベント Modelを開く方法を宣言するintentメソッド
-rw-r--r--core/lib/retriever/model.rb4
-rw-r--r--core/plugin/intent/.mikutter.yml11
-rw-r--r--core/plugin/intent/intent.rb96
-rw-r--r--core/plugin/intent/model/intent.rb8
-rw-r--r--core/plugin/intent/model/intent_token.rb20
-rw-r--r--core/plugin/message_detail_view/.mikutter.yml12
-rw-r--r--core/plugin/message_detail_view/message_detail_view.rb10
-rw-r--r--core/plugin/user_detail_view/.mikutter.yml1
-rw-r--r--core/plugin/user_detail_view/user_detail_view.rb11
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|