toot
", 32 | account = account), 33 | account = account, 34 | type = Notification.Type.Favourite.value), 35 | Notification( 36 | status = Status( 37 | content = "toot
", 38 | account = account), 39 | account = account, 40 | type = Notification.Type.Mention.value), 41 | Notification( 42 | status = Status( 43 | content = "toot
", 44 | account = account), 45 | account = account, 46 | type = Notification.Type.Reblog.value) 47 | ) 48 | ) 49 | )) 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/github/wakingrufus/mastodon/client/OAuthActions.kt: -------------------------------------------------------------------------------- 1 | package com.github.wakingrufus.mastodon.client 2 | 3 | import com.github.wakingrufus.mastodon.account.createAccountConfig 4 | import com.github.wakingrufus.mastodon.account.createAccountState 5 | import com.github.wakingrufus.mastodon.config.AccountConfig 6 | import com.github.wakingrufus.mastodon.config.ConfigurationHandler 7 | import com.github.wakingrufus.mastodon.config.FileConfigurationHandler 8 | import com.github.wakingrufus.mastodon.data.AccountState 9 | import com.github.wakingrufus.mastodon.data.OAuthModel 10 | import com.sys1yagi.mastodon4j.MastodonClient 11 | import com.sys1yagi.mastodon4j.api.Scope 12 | import com.sys1yagi.mastodon4j.api.entity.Notification 13 | import com.sys1yagi.mastodon4j.api.entity.auth.AccessToken 14 | import com.sys1yagi.mastodon4j.api.method.Accounts 15 | import com.sys1yagi.mastodon4j.api.method.Apps 16 | import mu.KotlinLogging 17 | 18 | private val logger = KotlinLogging.logger {} 19 | fun getOAuthUrl(oauthModel: OAuthModel): String { 20 | val apps = Apps(oauthModel.client) 21 | return apps.getOAuthUrl( 22 | clientId = oauthModel.appRegistration.clientId, 23 | scope = Scope(Scope.Name.ALL), 24 | redirectUri = oauthModel.appRegistration.redirectUri) 25 | } 26 | 27 | fun completeOAuth(oAuth: OAuthModel, 28 | onComplete: (AccountState) -> Unit, 29 | configHandler: ConfigurationHandler = FileConfigurationHandler(), 30 | accountStateCreator: (MastodonClient, (Notification) -> Unit) -> AccountState = ::createAccountState, 31 | accountConfigCreator: (Accounts, String, String, String, String) -> AccountConfig = ::createAccountConfig, 32 | accessTokenBuilder: (OAuthModel) -> AccessToken = ::getAccessToken, 33 | accountClientCreator: (String, String) -> MastodonClient = ::createAccountClient) { 34 | val accessToken = accessTokenBuilder.invoke(oAuth) 35 | val accountClient = accountClientCreator.invoke(oAuth.client.getInstanceName(), accessToken.accessToken) 36 | val accountState = accountStateCreator.invoke(accountClient, {System.out.println(it.toString())}) 37 | configHandler.saveConfig(configHandler.addAccountToConfig( 38 | configHandler.readFileConfig(), 39 | accountConfigCreator.invoke( 40 | Accounts(accountClient), 41 | accessToken.accessToken, 42 | oAuth.appRegistration.clientId, 43 | oAuth.appRegistration.clientSecret, 44 | accountClient.getInstanceName()))) 45 | onComplete.invoke(accountState) 46 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/github/wakingrufus/mastodon/ui/styles/DefaultStyles.kt: -------------------------------------------------------------------------------- 1 | package com.github.wakingrufus.mastodon.ui.styles 2 | 3 | import javafx.scene.Cursor 4 | import javafx.scene.layout.BorderStrokeStyle 5 | import javafx.scene.paint.Color 6 | import tornadofx.* 7 | 8 | 9 | class DefaultStyles : Stylesheet() { 10 | companion object { 11 | val smallButton by cssclass() 12 | val textInputLabel by cssclass() 13 | val textInput by cssclass() 14 | val defaultBorder by cssclass() 15 | 16 | val backdropColor = c ("#222222") 17 | val backgroundColor = c("#122e43") 18 | val darkestBackgroundColor = c("#061018") 19 | val darkerBackgroundColor = c("#0E2333") 20 | val linkColor = c("#AAAAFF") 21 | 22 | private val presetBackgroundColor = c("#061018") 23 | private val armedBackgroundColor = c("#2b6a9b") 24 | private val hoverBackgroundColor = c("#122e43") 25 | val textColor = c("#2b6a9b") 26 | val armedTextColor = Color.WHITE 27 | 28 | } 29 | 30 | init { 31 | smallButton { 32 | backgroundColor = multi(presetBackgroundColor) 33 | textFill = textColor 34 | backgroundRadius = multi(CssBox(10.px, 10.px, 10.px, 10.px)) 35 | backgroundInsets = multi(CssBox(0.px, 0.px, 0.px, 0.px)) 36 | fontSize = 3.em 37 | cursor = Cursor.HAND 38 | and(armed) { 39 | backgroundColor = multi(armedBackgroundColor) 40 | textFill = armedTextColor 41 | } 42 | and(hover) { 43 | backgroundColor = multi(hoverBackgroundColor) 44 | textFill = textColor 45 | } 46 | } 47 | textInputLabel { 48 | fontSize = 2.em 49 | minWidth = 10.em 50 | maxWidth = 50.percent 51 | } 52 | textInputLabel { 53 | fontSize = 3.em 54 | minWidth = 10.em 55 | maxWidth = 50.percent 56 | textFill = Color.WHITE 57 | } 58 | defaultBorder { 59 | borderColor = multi(CssBox( 60 | top = DefaultStyles.darkestBackgroundColor, 61 | bottom = DefaultStyles.darkestBackgroundColor, 62 | left = DefaultStyles.darkestBackgroundColor, 63 | right = DefaultStyles.darkestBackgroundColor 64 | )) 65 | borderWidth = multi(CssBox( 66 | top = .2.em, 67 | bottom = .2.em, 68 | left = .2.em, 69 | right = .2.em)) 70 | borderStyle = multi(BorderStrokeStyle.SOLID) 71 | } 72 | 73 | } 74 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/github/wakingrufus/mastodon/ui/OAuthViewTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.wakingrufus.mastodon.ui 2 | 3 | import com.github.wakingrufus.mastodon.TornadoFxTest 4 | import com.github.wakingrufus.mastodon.data.AccountState 5 | import com.github.wakingrufus.mastodon.data.OAuthModel 6 | import com.github.wakingrufus.mastodon.waitFor 7 | import com.nhaarman.mockito_kotlin.mock 8 | import com.sys1yagi.mastodon4j.api.entity.auth.AppRegistration 9 | import mu.KLogging 10 | import org.junit.Test 11 | import org.testfx.api.FxAssert 12 | import org.testfx.matcher.base.NodeMatchers 13 | import kotlin.test.assertEquals 14 | 15 | class OAuthViewTest : TornadoFxTest() { 16 | companion object : KLogging() 17 | 18 | @Test 19 | fun render() { 20 | val onComplete: (AccountState) -> Unit = {} 21 | showViewWithParamsFishing
text before link https://www.gamingonlinux.com/articles/fishing-planet-leaves-early-access-with-full-linux-support-also-has-the-unity-fullscreen-bug.10242 #Linux #LinuxGaming
" 22 | val sampleToot2: String = "RT @plsburydoughboy Is it gay to dive into the Marianas Trench you're entering a power bottom
\n" 23 | 24 | @Test 25 | fun parseToot() { 26 | val actual: Pane = parseToot(content = sampleToot1) 27 | logger.info { actual.toString() } 28 | val node: VBox = actual.children[0] as VBox 29 | logger.info { node.toString() } 30 | assertEquals(2, node.children.size, "2 paragraphs") 31 | val par1: TextFlow = node.children[0] as TextFlow 32 | val par1Text = par1.children[0] as Text 33 | assertEquals("Fishing", par1Text.text) 34 | val par2: TextFlow = node.children[1] as TextFlow 35 | // assertEquals(4, node.children.size, "2nd paragraph has 4 children") 36 | val par2Text: Text = par2.children[0] as Text 37 | assertEquals("text before link ", par2Text.text) 38 | val par2link1: Hyperlink = par2.children[1] as Hyperlink 39 | assertEquals("https://www.gamingonlinux.com/articles/fishing-planet-leaves-early-access-with-full-linux-support-also-has-the-unity-fullscreen-bug.10242", 40 | par2link1.text) 41 | val par2Text2: Text = par2.children[2] as Text 42 | assertEquals(" ", par2Text2.text) 43 | val par2link2: Hyperlink = par2.children[3] as Hyperlink 44 | assertEquals("#Linux", par2link2.text) 45 | val par2Text3: Text = par2.children[4] as Text 46 | assertEquals(" ", par2Text3.text) 47 | val par2link3: Hyperlink = par2.children[5] as Hyperlink 48 | assertEquals("#LinuxGaming", par2link3.text) 49 | } 50 | 51 | @Throws(Exception::class) 52 | override fun start(stage: Stage) { 53 | JFXPanel() 54 | val load: Parent = HBox() 55 | val scene = Scene(load, 800.0, 600.0) 56 | stage.scene = scene 57 | stage.show() 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/github/wakingrufus/mastodon/ui/OAuthView.kt: -------------------------------------------------------------------------------- 1 | package com.github.wakingrufus.mastodon.ui 2 | 3 | import com.github.wakingrufus.mastodon.client.completeOAuth 4 | import com.github.wakingrufus.mastodon.client.createServerClient 5 | import com.github.wakingrufus.mastodon.client.getOAuthUrl 6 | import com.github.wakingrufus.mastodon.client.registerApp 7 | import com.github.wakingrufus.mastodon.data.AccountState 8 | import com.github.wakingrufus.mastodon.data.OAuthModel 9 | import com.github.wakingrufus.mastodon.ui.styles.DefaultStyles 10 | import com.sys1yagi.mastodon4j.MastodonClient 11 | import com.sys1yagi.mastodon4j.api.entity.auth.AppRegistration 12 | import javafx.scene.control.TextField 13 | import javafx.scene.layout.VBox 14 | import javafx.scene.paint.Color 15 | import mu.KLogging 16 | import tornadofx.* 17 | 18 | class OAuthView : Fragment() { 19 | companion object : KLogging() 20 | 21 | val buildModel: (String) -> OAuthModel by param(defaultValue = {serverUrl: String -> 22 | val client = createServerClient(serverUrl) 23 | OAuthModel(appRegistration = registerApp(client)!!, client = client) 24 | }) 25 | val onComplete: (AccountState) -> Unit by param() 26 | val oAuthUrlBuilder: (OAuthModel) -> String by param(::getOAuthUrl) 27 | val completeOAuthFunction: (OAuthModel) -> Unit by param({ model -> 28 | completeOAuth(oAuth = model, onComplete = onComplete) 29 | }) 30 | 31 | lateinit var serverField: TextField 32 | lateinit var vbox: VBox 33 | lateinit var tokenField: TextField 34 | lateinit var loginWrapper: VBox 35 | override val root = vbox { 36 | id = "oauth-root" 37 | style { 38 | minWidth = 100.percent 39 | minHeight = 100.percent 40 | backgroundColor = multi(Color.rgb(0x06, 0x10, 0x18)) 41 | padding = CssBox(top = 1.px, right = 1.px, bottom = 1.px, left = 1.px) 42 | } 43 | hbox { 44 | id = "instance-form" 45 | style { 46 | backgroundColor = multi(DefaultStyles.backgroundColor) 47 | } 48 | label("Server") { 49 | id = "instance-field-label" 50 | addClass(DefaultStyles.textInputLabel) 51 | } 52 | serverField = textfield { 53 | id = "instance-field" 54 | addClass(DefaultStyles.textInput) 55 | } 56 | button("Get Token") { 57 | id = "instance-form-submit" 58 | addClass(DefaultStyles.smallButton) 59 | action { 60 | showLogin(serverField.text) 61 | } 62 | } 63 | } 64 | loginWrapper = vbox { 65 | id = "login-wrapper" 66 | } 67 | } 68 | 69 | fun showLogin(serverUrl: String) { 70 | loginWrapper.clear() 71 | val oAuthModel = buildModel(serverUrl) 72 | loginWrapper += webview { 73 | id = "instance-login" 74 | engine?.load(oAuthUrlBuilder.invoke(oAuthModel)) 75 | } 76 | loginWrapper += hbox { 77 | id = "token-form" 78 | label("Token") { 79 | addClass(DefaultStyles.textInputLabel) 80 | } 81 | tokenField = textfield { 82 | } 83 | button("Login") { 84 | addClass(DefaultStyles.smallButton) 85 | action { 86 | completeOAuthFunction(oAuthModel.copy(token = tokenField.text)) 87 | } 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/github/wakingrufus/mastodon/ui/NotificationFragment.kt: -------------------------------------------------------------------------------- 1 | package com.github.wakingrufus.mastodon.ui 2 | 3 | import com.github.wakingrufus.mastodon.ui.styles.DefaultStyles 4 | import com.sys1yagi.mastodon4j.api.entity.Notification 5 | import javafx.geometry.Pos 6 | import javafx.scene.paint.Color 7 | import mu.KLogging 8 | import tornadofx.* 9 | 10 | class NotificationFragment : Fragment() { 11 | companion object : KLogging() 12 | 13 | val server: String by param() 14 | val notification: Notification by param() 15 | 16 | override val root = vbox { 17 | hbox { 18 | style { 19 | backgroundColor = multi(DefaultStyles.backgroundColor) 20 | } 21 | label(notification.account?.displayName!!) { 22 | textFill = Color.WHITE 23 | style { 24 | padding = CssBox(1.px, 1.px, 1.px, 1.px) 25 | fontSize = 1.5.em 26 | } 27 | } 28 | if (notification.type == Notification.Type.Follow.value) { 29 | label(" followed you.") { 30 | textFill = Color.WHITE 31 | style { 32 | padding = CssBox(1.px, 1.px, 1.px, 1.px) 33 | fontSize = 1.5.em 34 | } 35 | } 36 | } else if (notification.type == Notification.Type.Reblog.value) { 37 | label(" boosted your toot.") { 38 | textFill = Color.WHITE 39 | style { 40 | padding = CssBox(1.px, 1.px, 1.px, 1.px) 41 | fontSize = 1.5.em 42 | } 43 | } 44 | } else if (notification.type == Notification.Type.Favourite.value) { 45 | label(" favourited your toot") { 46 | textFill = Color.WHITE 47 | style { 48 | padding = CssBox(1.px, 1.px, 1.px, 1.px) 49 | fontSize = 1.5.em 50 | } 51 | } 52 | } else if (notification.type == Notification.Type.Mention.value) { 53 | label(" mentioned you") { 54 | textFill = Color.WHITE 55 | style { 56 | padding = CssBox(1.px, 1.px, 1.px, 1.px) 57 | fontSize = 1.5.em 58 | } 59 | } 60 | } 61 | } 62 | hbox { 63 | if (notification.type == Notification.Type.Follow.value 64 | || notification.type == Notification.Type.Mention.value) 65 | this += find