1 module main_page; 2 3 import std.concurrency; 4 import std.file; 5 import std.json; 6 import std.typecons; 7 import std.stdio; 8 9 import awebview.wrapper; 10 import awebview.gui.html; 11 import awebview.gui.datapack; 12 import awebview.gui.application; 13 import awebview.gui.activity; 14 import awebview.gui.widgets.button; 15 import awebview.gui.widgets.text; 16 17 import graphite.twitter; 18 19 import carbon.functional; 20 21 import msgpack; 22 import lock_free.dlist; 23 24 import consts; 25 import oauth_page; 26 import tweet_table; 27 28 29 class MainPage : TemplateHTMLPage!(import(`main_page.html`)) 30 { 31 private 32 alias NormalButton = InputButton!(["class": "btn btn-xs btn-primary"]); 33 34 private 35 alias TweetTextArea = TextArea!(); 36 37 private 38 alias PackedDataType = DataPack!(bool, Twitter); 39 40 41 this() 42 { 43 super("mainPage"); 44 45 _tweetTable = new TweetTable("tweetTable"); 46 this ~= _tweetTable; 47 48 this ~= new TweetTextArea(`iptTweetText`); 49 50 this ~= (new NormalButton(`btnTweet`)).observe!((a){ 51 a.onClick.connect!"onClickTweet"(this); 52 a.staticProps["value"] = "ツイート"; 53 }); 54 } 55 56 57 override 58 void onStart(Activity activity) 59 { 60 if(auto p = this.id in activity.application.savedData){ 61 auto origin = *p; 62 auto pd = PackedDataType.unpack(*p); 63 64 if(pd.field[0]) 65 _twTkn = pd.field[1]; 66 67 *p = pd.parent; 68 super.onStart(activity); 69 *p = origin; 70 } 71 else 72 { 73 super.onStart(activity); 74 } 75 } 76 77 78 override 79 void onLoad(bool isInit) 80 { 81 super.onLoad(isInit); 82 83 if(this._twTkn.isNull) 84 { 85 if(activity["oauthPage"].to!OAuthPage.token.isNull) 86 activity.load("oauthPage"); 87 else{ 88 _twTkn = activity["oauthPage"].to!OAuthPage.token; 89 connectUserStream(); 90 } 91 } 92 else 93 connectUserStream(); 94 } 95 96 97 override 98 void onDestroy() 99 { 100 super.onDestroy(); 101 102 if(!_twTkn.isNull){ 103 PackedDataType pd; 104 105 if(auto p = this.id in SDLApplication.instance.savedData) 106 pd.parent = *p; 107 108 pd.field[0] = !_twTkn.isNull; 109 if(!_twTkn.isNull) 110 pd.field[1] = _twTkn.get; 111 112 SDLApplication.instance.savedData[this.id] = pd.pack(); 113 114 _usTid.send(false); // send dummy message 115 } 116 } 117 118 119 void connectUserStream() 120 { 121 auto res = _twTkn.callAPI!"userstream.user"(null); 122 _us = res.channel; 123 _usTid = res.tid; 124 } 125 126 127 override 128 void onUpdate() 129 { 130 super.onUpdate(); 131 132 while(1) 133 { 134 if(auto p = _us.popFront()){ 135 try{ 136 string tw = *p; 137 auto json = parseJSON(tw); 138 _tweetTable.addTweet(json["user"]["profile_image_url"].str, json["user"]["name"].str, json["text"].str); 139 } 140 catch(Exception){} 141 } 142 else 143 break; 144 } 145 } 146 147 148 void onClickTweet(FiredContext ctx, WeakRef!(const(JSArrayCpp)) args) 149 { 150 auto txtArea = elements["iptTweetText"].to!(TextArea!()); 151 152 auto tweetText = txtArea.text(); 153 if(tweetText.length){ 154 _twTkn.callAPI!"statuses.update"(["status": tweetText]); 155 txtArea.text = ""; 156 } 157 } 158 159 160 private: 161 TweetTable _tweetTable; 162 Nullable!Twitter _twTkn; 163 shared(AtomicDList!string) _us; 164 Tid _usTid; 165 }