17 | fun removeUser(userRecord: AuthUserRecord)
18 | }
19 |
20 | /**
21 | * 1つのエンドポイントに対応するストリーミング通信管理の実装。
22 | */
23 | interface StreamChannel {
24 | val channelId: String
25 | val channelName: String
26 | val userRecord: AuthUserRecord
27 | val allowUserControl: Boolean
28 | val isRunning: Boolean
29 |
30 | fun start()
31 | fun stop()
32 | }
--------------------------------------------------------------------------------
/Yukari/src/test/java/shibafu/yukari/util/StringUtilTest.java:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.util;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | /**
7 | * Created by shibafu on 15/06/24.
8 | */
9 | public class StringUtilTest {
10 |
11 | @Test
12 | public void testCompressText() throws Exception {
13 | Assert.assertEquals("【悲報】", StringUtil.compressText("【悲報】\n【悲報】\n【悲報】\n【悲報】"));
14 | Assert.assertEquals("【悲報】", StringUtil.compressText("【悲報】 \n【悲報】\n【悲報】 \n【悲報】 "));
15 | Assert.assertNull(StringUtil.compressText("【悲報】\n【悲報】\n【悲報】"));
16 | Assert.assertEquals("[゚д゚]", StringUtil.compressText("[゚д゚]\n[゚д゚]\n[゚д゚]\n[゚д゚]"));
17 | Assert.assertNull(StringUtil.compressText("[゚д゚]\n[゚д゚]\n[゚д゚]"));
18 | Assert.assertEquals("↓", StringUtil.compressText("わかる\n↓\nウケる\n↓\n神\n↓\nわかる\n↓\nウケる\n↓\n神"));
19 | }
20 | }
--------------------------------------------------------------------------------
/Yukari/src/main/java/shibafu/yukari/mastodon/entity/DonMention.kt:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.mastodon.entity
2 |
3 | import com.sys1yagi.mastodon4j.api.entity.Mention
4 | import shibafu.yukari.database.Provider
5 | import shibafu.yukari.mastodon.MastodonUtil
6 | import shibafu.yukari.database.AuthUserRecord
7 | import shibafu.yukari.entity.Mention as IMention
8 |
9 | class DonMention(mention: Mention) : IMention {
10 | override val id: Long = mention.id
11 |
12 | override val url: String = mention.url
13 |
14 | override val screenName: String = MastodonUtil.expandFullScreenName(mention.acct, mention.url)
15 |
16 | override fun isMentionedTo(userRecord: AuthUserRecord): Boolean {
17 | if (userRecord.Provider.apiType != Provider.API_MASTODON) {
18 | return false
19 | }
20 |
21 | return userRecord.ScreenName == screenName
22 | }
23 | }
--------------------------------------------------------------------------------
/api/mastodon-ws/src/main/java/info/shibafu528/yukari/api/mastodon/ws/StreamListener.kt:
--------------------------------------------------------------------------------
1 | package info.shibafu528.yukari.api.mastodon.ws
2 |
3 | import com.sys1yagi.mastodon4j.api.entity.Notification
4 | import com.sys1yagi.mastodon4j.api.entity.Status
5 | import okhttp3.Response
6 |
7 | /**
8 | * サーバから受け取った各種イベントを購読するためのインターフェースです。
9 | */
10 | interface StreamListener {
11 | fun onUpdate(status: Status)
12 | fun onNotification(notification: Notification)
13 | fun onDelete(id: Long)
14 |
15 | /**
16 | * 接続が確立された時に呼び出されます。
17 | */
18 | fun onOpen()
19 |
20 | /**
21 | * 通信が正常に終了し、切断された時に呼び出されます。[onFailure] とは排他的な関係にあり、切断時にはどちらか一方が呼び出されます。
22 | */
23 | fun onClosed()
24 |
25 | /**
26 | * エラーにより通信が異常終了した時に呼び出されます。[onClosed] とは排他的な関係にあり、切断時にはどちらか一方が呼び出されます。
27 | */
28 | fun onFailure(t: Throwable, response: Response?)
29 | }
--------------------------------------------------------------------------------
/Yukari/src/main/java/shibafu/yukari/common/span/HashTagSpan.java:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.common.span;
2 |
3 | import android.content.Intent;
4 | import androidx.annotation.NonNull;
5 | import android.text.style.ClickableSpan;
6 | import android.view.View;
7 | import shibafu.yukari.activity.MainActivity;
8 |
9 | public class HashTagSpan extends ClickableSpan {
10 | private String tag;
11 |
12 | public HashTagSpan(String tag) {
13 | if (tag.startsWith("#")) {
14 | this.tag = tag;
15 | } else {
16 | this.tag = "#" + tag;
17 | }
18 | }
19 |
20 | @Override
21 | public void onClick(@NonNull View widget) {
22 | Intent intent = new Intent(widget.getContext(), MainActivity.class);
23 | intent.putExtra(MainActivity.EXTRA_SEARCH_WORD, tag);
24 | widget.getContext().startActivity(intent);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/yukari-processor/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'kotlin'
3 |
4 | repositories {
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | implementation project(':yukari-processor-annotation')
10 | implementation 'com.squareup:javapoet:1.2.0'
11 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
12 | }
13 |
14 | buildscript {
15 | ext.kotlin_version = '1.9.25'
16 | repositories {
17 | mavenCentral()
18 | }
19 | dependencies {
20 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
21 | }
22 | }
23 |
24 | def defaultEncoding = 'UTF-8'
25 | compileJava {
26 | options.encoding = defaultEncoding
27 | }
28 | compileTestJava {
29 | options.encoding = defaultEncoding
30 | }
31 |
32 | java {
33 | toolchain {
34 | languageVersion = JavaLanguageVersion.of(8)
35 | }
36 | }
--------------------------------------------------------------------------------
/Yukari/src/main/res/layout/menu_profile_manage_follow.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
22 |
--------------------------------------------------------------------------------
/Yukari/src/main/res/layout/row_intent.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
14 |
15 |
23 |
--------------------------------------------------------------------------------
/Yukari/src/main/res/layout/view_morse.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
13 |
14 |
22 |
23 |
--------------------------------------------------------------------------------
/Yukari/src/main/java/shibafu/yukari/common/span/UserProfileSpan.java:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.common.span;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import androidx.annotation.NonNull;
6 | import android.text.style.ClickableSpan;
7 | import android.view.View;
8 | import shibafu.yukari.activity.ProfileActivity;
9 | import shibafu.yukari.database.AuthUserRecord;
10 |
11 | public class UserProfileSpan extends ClickableSpan {
12 | private AuthUserRecord userRecord;
13 | private String url;
14 |
15 | public UserProfileSpan(AuthUserRecord userRecord, String url) {
16 | this.userRecord = userRecord;
17 | this.url = url;
18 | }
19 |
20 | @Override
21 | public void onClick(@NonNull View widget) {
22 | Intent intent = ProfileActivity.newIntent(widget.getContext(), userRecord, Uri.parse(url));
23 | widget.getContext().startActivity(intent);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Yukari/src/main/res/layout/fragment_oauth_provider.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
21 |
--------------------------------------------------------------------------------
/Yukari/src/main/java/shibafu/yukari/common/async/TwitterAsyncTask.java:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.common.async;
2 |
3 | import android.content.Context;
4 | import android.widget.Toast;
5 |
6 | import twitter4j.TwitterException;
7 |
8 | /**
9 | * Created by Shibafu on 13/11/23.
10 | */
11 | public abstract class TwitterAsyncTask extends ParallelAsyncTask
{
12 | private Context context;
13 |
14 | protected TwitterAsyncTask(Context context) {
15 | this.context = context;
16 | }
17 |
18 | @Override
19 | protected void onPostExecute(TwitterException e) {
20 | super.onPostExecute(e);
21 | if (e != null) {
22 | Toast.makeText(context,
23 | String.format("通信エラー: %d\n%s",
24 | e.getErrorCode(),
25 | e.getErrorMessage()),
26 | Toast.LENGTH_LONG).show();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Yukari/src/main/java/shibafu/yukari/fragment/PostProgressDialogFragment.java:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.fragment;
2 |
3 | import android.app.Dialog;
4 | import android.app.ProgressDialog;
5 | import android.os.Bundle;
6 | import androidx.fragment.app.DialogFragment;
7 |
8 | /**
9 | * Created by shibafu on 14/08/05.
10 | */
11 | public class PostProgressDialogFragment extends DialogFragment {
12 | public static PostProgressDialogFragment newInstance() {
13 | PostProgressDialogFragment fragment = new PostProgressDialogFragment();
14 | fragment.setCancelable(false);
15 | return fragment;
16 | }
17 |
18 | @Override
19 | public Dialog onCreateDialog(Bundle savedInstanceState) {
20 | ProgressDialog pd = new ProgressDialog(getActivity());
21 | pd.setMessage("送信中...");
22 | pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
23 | pd.setIndeterminate(true);
24 | return pd;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Yukari/src/main/java/shibafu/yukari/activity/LicenseActivity.java:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.activity;
2 |
3 |
4 | import android.os.Bundle;
5 | import android.view.MenuItem;
6 | import android.webkit.WebView;
7 |
8 | import shibafu.yukari.activity.base.ActionBarYukariBase;
9 |
10 | public class LicenseActivity extends ActionBarYukariBase {
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | WebView wv = new WebView(this);
16 | wv.loadUrl("file:///android_asset/about.html");
17 | setContentView(wv);
18 |
19 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
20 | }
21 |
22 | @Override
23 | public boolean onOptionsItemSelected(MenuItem item) {
24 | switch (item.getItemId()) {
25 | case android.R.id.home:
26 | finish();
27 | return true;
28 | }
29 | return super.onOptionsItemSelected(item);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Yukari/src/main/java/shibafu/yukari/mastodon/api/AccountsEx.kt:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.mastodon.api
2 |
3 | import com.sys1yagi.mastodon4j.MastodonClient
4 | import com.sys1yagi.mastodon4j.MastodonRequest
5 | import com.sys1yagi.mastodon4j.api.entity.Relationship
6 | import com.sys1yagi.mastodon4j.extension.emptyRequestBody
7 |
8 | class AccountsEx(private val client: MastodonClient) {
9 | /**
10 | * POST /api/v1/accounts/:id/remove_from_followers
11 | *
12 | * [Document](https://docs.joinmastodon.org/methods/accounts/#remove_from_followers)
13 | */
14 | fun postRemoveFromFollowers(accountId: Long): MastodonRequest {
15 | return MastodonRequest(
16 | {
17 | client.post("accounts/$accountId/remove_from_followers", emptyRequestBody())
18 | },
19 | {
20 | client.getSerializer().fromJson(it, Relationship::class.java)
21 | }
22 | )
23 | }
24 | }
--------------------------------------------------------------------------------
/Yukari/src/main/java/shibafu/yukari/media2/impl/Twitpic.java:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.media2.impl;
2 |
3 | import androidx.annotation.NonNull;
4 | import org.jsoup.Jsoup;
5 | import shibafu.yukari.media2.MemoizeMedia;
6 |
7 | import java.io.IOException;
8 | import java.net.URL;
9 |
10 | public class Twitpic extends MemoizeMedia {
11 | /**
12 | * @param browseUrl メディアの既知のURL
13 | */
14 | public Twitpic(@NonNull String browseUrl) {
15 | super(browseUrl);
16 | }
17 |
18 | @Override
19 | protected String resolveMediaUrl() throws IOException {
20 | return Jsoup.parse(new URL(getBrowseUrl()), 10000)
21 | .select("meta[name=twitter:image]")
22 | .attr("value");
23 | }
24 |
25 | @Override
26 | protected String resolveThumbnailUrl() throws IOException {
27 | return resolveMediaUrl();
28 | }
29 |
30 | @Override
31 | public boolean canPreview() {
32 | return true;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Yukari/src/main/java/shibafu/yukari/media2/impl/Pixiv.java:
--------------------------------------------------------------------------------
1 | package shibafu.yukari.media2.impl;
2 |
3 | import androidx.annotation.NonNull;
4 | import org.jsoup.Jsoup;
5 | import shibafu.yukari.media2.MemoizeMedia;
6 |
7 | import java.io.IOException;
8 |
9 | public class Pixiv extends MemoizeMedia {
10 | /**
11 | * @param browseUrl メディアの既知のURL
12 | */
13 | public Pixiv(@NonNull String browseUrl) {
14 | super(browseUrl);
15 | }
16 |
17 | @Override
18 | public String resolveMediaUrl() throws IOException {
19 | return getBrowseUrl();
20 | }
21 |
22 | @Override
23 | public String resolveThumbnailUrl() throws IOException {
24 | return Jsoup.connect(getBrowseUrl())
25 | .timeout(10000)
26 | .get()
27 | .select("meta[property=og:image]")
28 | .attr("content");
29 | }
30 |
31 | @Override
32 | public boolean canPreview() {
33 | return false;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------