mirror of
https://github.com/muesli/telephant
synced 2024-11-22 19:33:06 +00:00
Added support for attaching images to posts
This commit is contained in:
parent
53855adda8
commit
81bc8a4840
8 changed files with 254 additions and 10 deletions
|
@ -36,6 +36,7 @@ type Follow struct {
|
|||
|
||||
// Media describes a media item.
|
||||
type Media struct {
|
||||
ID string
|
||||
Preview string
|
||||
URL string
|
||||
}
|
||||
|
|
|
@ -172,22 +172,51 @@ func (mod *Account) Logo() string {
|
|||
}
|
||||
|
||||
// Post posts a new status
|
||||
func (mod *Account) Post(message string) error {
|
||||
_, err := mod.client.PostStatus(context.Background(), &mastodon.Toot{
|
||||
func (mod *Account) Post(message string, attachments []string) error {
|
||||
t := &mastodon.Toot{
|
||||
Status: message,
|
||||
})
|
||||
}
|
||||
for _, v := range attachments {
|
||||
t.MediaIDs = append(t.MediaIDs, mastodon.ID(v))
|
||||
}
|
||||
|
||||
_, err := mod.client.PostStatus(context.Background(), t)
|
||||
return err
|
||||
}
|
||||
|
||||
// Reply posts a new reply-status
|
||||
func (mod *Account) Reply(replyid string, message string) error {
|
||||
_, err := mod.client.PostStatus(context.Background(), &mastodon.Toot{
|
||||
func (mod *Account) Reply(replyid string, message string, attachments []string) error {
|
||||
t := &mastodon.Toot{
|
||||
Status: message,
|
||||
InReplyToID: mastodon.ID(replyid),
|
||||
})
|
||||
}
|
||||
for _, v := range attachments {
|
||||
t.MediaIDs = append(t.MediaIDs, mastodon.ID(v))
|
||||
}
|
||||
|
||||
_, err := mod.client.PostStatus(context.Background(), t)
|
||||
return err
|
||||
}
|
||||
|
||||
func (mod *Account) UploadAttachment(url string) {
|
||||
go func() {
|
||||
a, err := mod.client.UploadMedia(context.Background(), url)
|
||||
if err != nil {
|
||||
ev := accounts.ErrorEvent{
|
||||
Message: err.Error(),
|
||||
Internal: false,
|
||||
}
|
||||
mod.evchan <- ev
|
||||
return
|
||||
}
|
||||
|
||||
mod.evchan <- accounts.Media{
|
||||
ID: string(a.ID),
|
||||
Preview: a.PreviewURL,
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// DeletePost deletes a post
|
||||
func (mod *Account) DeletePost(id string) error {
|
||||
err := mod.client.DeleteStatus(context.Background(), mastodon.ID(id))
|
||||
|
|
122
attachmentmodel.go
Normal file
122
attachmentmodel.go
Normal file
|
@ -0,0 +1,122 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/therecipe/qt/core"
|
||||
)
|
||||
|
||||
// Model Roles
|
||||
const (
|
||||
AttachmentID = int(core.Qt__UserRole) + 1<<iota
|
||||
AttachmentPreview
|
||||
)
|
||||
|
||||
// AttachmentModel holds a collection of attachments
|
||||
type AttachmentModel struct {
|
||||
core.QAbstractListModel
|
||||
|
||||
_ func() `constructor:"init"`
|
||||
|
||||
_ map[int]*core.QByteArray `property:"roles"`
|
||||
_ []*Attachment `property:"attachments"`
|
||||
|
||||
_ func(*Attachment) `slot:"addAttachment"`
|
||||
_ func(row int) `slot:"removeAttachment"`
|
||||
_ func() `slot:"clear"`
|
||||
}
|
||||
|
||||
// Attachment represents a single attachment
|
||||
type Attachment struct {
|
||||
core.QObject
|
||||
|
||||
ID string
|
||||
Preview string
|
||||
URL string
|
||||
}
|
||||
|
||||
func (m *AttachmentModel) init() {
|
||||
m.SetRoles(map[int]*core.QByteArray{
|
||||
AttachmentID: core.NewQByteArray2("attachmentID", -1),
|
||||
AttachmentPreview: core.NewQByteArray2("attachmentPreview", -1),
|
||||
})
|
||||
|
||||
m.ConnectData(m.data)
|
||||
m.ConnectSetData(m.setData)
|
||||
m.ConnectRowCount(m.rowCount)
|
||||
m.ConnectColumnCount(m.columnCount)
|
||||
m.ConnectRoleNames(m.roleNames)
|
||||
|
||||
m.ConnectAddAttachment(m.addAttachment)
|
||||
m.ConnectRemoveAttachment(m.removeAttachment)
|
||||
m.ConnectClear(m.clear)
|
||||
}
|
||||
|
||||
func (m *AttachmentModel) setData(index *core.QModelIndex, value *core.QVariant, role int) bool {
|
||||
if !index.IsValid() {
|
||||
return false
|
||||
}
|
||||
|
||||
m.DataChanged(index, index, []int{Editing})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *AttachmentModel) data(index *core.QModelIndex, role int) *core.QVariant {
|
||||
if !index.IsValid() {
|
||||
return core.NewQVariant()
|
||||
}
|
||||
if index.Row() >= len(m.Attachments()) {
|
||||
return core.NewQVariant()
|
||||
}
|
||||
|
||||
var p = m.Attachments()[index.Row()]
|
||||
switch role {
|
||||
case AttachmentID:
|
||||
{
|
||||
return core.NewQVariant14(p.ID)
|
||||
}
|
||||
case AttachmentPreview:
|
||||
{
|
||||
return core.NewQVariant14(p.Preview)
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return core.NewQVariant()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *AttachmentModel) rowCount(parent *core.QModelIndex) int {
|
||||
return len(m.Attachments())
|
||||
}
|
||||
|
||||
func (m *AttachmentModel) columnCount(parent *core.QModelIndex) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (m *AttachmentModel) roleNames() map[int]*core.QByteArray {
|
||||
return m.Roles()
|
||||
}
|
||||
|
||||
func (m *AttachmentModel) clear() {
|
||||
m.BeginResetModel()
|
||||
m.SetAttachments([]*Attachment{})
|
||||
m.EndResetModel()
|
||||
}
|
||||
|
||||
func (m *AttachmentModel) addAttachment(p *Attachment) {
|
||||
m.BeginInsertRows(core.NewQModelIndex(), len(m.Attachments()), len(m.Attachments()))
|
||||
m.SetAttachments(append(m.Attachments(), p))
|
||||
m.EndInsertRows()
|
||||
}
|
||||
|
||||
func (m *AttachmentModel) removeAttachment(row int) {
|
||||
m.BeginRemoveRows(core.NewQModelIndex(), row, row)
|
||||
m.SetAttachments(append(m.Attachments()[:row], m.Attachments()[row+1:]...))
|
||||
m.EndRemoveRows()
|
||||
}
|
||||
|
||||
func init() {
|
||||
AttachmentModel_QRegisterMetaType()
|
||||
Attachment_QRegisterMetaType()
|
||||
}
|
|
@ -21,6 +21,7 @@ type UIBridge struct {
|
|||
_ func(id string) `slot:"likeButton"`
|
||||
_ func(id string) `slot:"unlikeButton"`
|
||||
_ func(id string, follow bool) `slot:"followButton"`
|
||||
_ func(url string) `slot:"uploadAttachment"`
|
||||
_ func(id string) `slot:"loadConversation"`
|
||||
_ func(id string) `slot:"loadAccount"`
|
||||
_ func(token string) `slot:"tag"`
|
||||
|
@ -49,6 +50,7 @@ type AccountBridge struct {
|
|||
|
||||
_ *core.QAbstractListModel `property:"panes"`
|
||||
_ *core.QAbstractListModel `property:"notifications"`
|
||||
_ *core.QAbstractListModel `property:"attachments"`
|
||||
_ *core.QAbstractListModel `property:"conversation"`
|
||||
_ *core.QAbstractListModel `property:"accountMessages"`
|
||||
}
|
||||
|
@ -111,6 +113,7 @@ func setupQmlBridges() {
|
|||
uiBridge.ConnectLikeButton(like)
|
||||
uiBridge.ConnectUnlikeButton(unlike)
|
||||
uiBridge.ConnectFollowButton(follow)
|
||||
uiBridge.ConnectUploadAttachment(uploadAttachment)
|
||||
uiBridge.ConnectLoadConversation(loadConversation)
|
||||
uiBridge.ConnectLoadAccount(loadAccount)
|
||||
uiBridge.ConnectTag(tag)
|
||||
|
|
|
@ -79,6 +79,14 @@ func handleEvents(eventsIn chan interface{}, messages *MessageModel) {
|
|||
log.Println("Error:", event.Message)
|
||||
accountBridge.SetError(event.Message)
|
||||
}
|
||||
case accounts.Media:
|
||||
{
|
||||
log.Printf("Added attachment: %+v\n", event)
|
||||
var p = NewAttachment(nil)
|
||||
p.ID = event.ID
|
||||
p.Preview = event.Preview
|
||||
attachmentModel.AddAttachment(p)
|
||||
}
|
||||
case accounts.MessageEvent:
|
||||
{
|
||||
// spw := &spew.ConfigState{Indent: " ", DisableCapacities: true, DisablePointerAddresses: true}
|
||||
|
|
|
@ -21,6 +21,40 @@ Popup {
|
|||
clip: true
|
||||
contentHeight: layout.height
|
||||
|
||||
BusyIndicator {
|
||||
z: 1
|
||||
id: busy
|
||||
running: false
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
DropArea {
|
||||
id: drop
|
||||
anchors.fill: parent
|
||||
enabled: true
|
||||
|
||||
onEntered:
|
||||
console.log("entered")
|
||||
|
||||
onExited:
|
||||
console.log("exited")
|
||||
|
||||
onDropped: {
|
||||
console.log("dropped", drop.urls.length, "urls")
|
||||
|
||||
for (var i = 0; i < drop.urls.length; i++) {
|
||||
console.log(drop.urls[i])
|
||||
|
||||
busy.running = true
|
||||
var media = uiBridge.uploadAttachment(drop.urls[i])
|
||||
/*if (media != '') {
|
||||
attachments.append({"id": media, "url": drop.urls[i]})
|
||||
}*/
|
||||
}
|
||||
drop.acceptProposedAction()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
width: parent.width
|
||||
|
@ -47,6 +81,37 @@ Popup {
|
|||
wrapMode: TextArea.Wrap
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: accountBridge.attachments
|
||||
onRowsInserted: {
|
||||
busy.running = false
|
||||
}
|
||||
onRowsRemoved: {
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: attachmentLayout
|
||||
Layout.fillWidth: true
|
||||
Repeater {
|
||||
model: accountBridge.attachments
|
||||
Image {
|
||||
smooth: true
|
||||
source: model.attachmentPreview
|
||||
sourceSize.height: 64
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: function() {
|
||||
accountBridge.attachments.removeAttachment(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ function createMessagePopup(parent, model) {
|
|||
"message": model
|
||||
})
|
||||
|
||||
accountBridge.attachments.clear()
|
||||
|
||||
if (popup == null) {
|
||||
console.log("Error creating MessagePopup")
|
||||
}
|
||||
|
|
22
telephant.go
22
telephant.go
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
@ -22,6 +23,7 @@ var (
|
|||
notificationModel = NewMessageModel(nil)
|
||||
conversationModel = NewMessageModel(nil)
|
||||
accountMessagesModel = NewMessageModel(nil)
|
||||
attachmentModel = NewAttachmentModel(nil)
|
||||
paneModel = NewPaneModel(nil)
|
||||
)
|
||||
|
||||
|
@ -84,13 +86,18 @@ func postLimitCount(body string) int {
|
|||
// reply is used to post a new message
|
||||
// if replyid is > 0, it's send as a reply
|
||||
func reply(replyid string, message string) {
|
||||
var attachments []string
|
||||
for _, v := range attachmentModel.Attachments() {
|
||||
attachments = append(attachments, v.ID)
|
||||
}
|
||||
|
||||
var err error
|
||||
if replyid != "" {
|
||||
log.Println("Sending reply to:", replyid, message)
|
||||
err = tc.Reply(replyid, message)
|
||||
log.Println("Sending reply to:", replyid, attachments, message)
|
||||
err = tc.Reply(replyid, message, attachments)
|
||||
} else {
|
||||
log.Println("Posting:", message)
|
||||
err = tc.Post(message)
|
||||
log.Println("Posting:", attachments, message)
|
||||
err = tc.Post(message, attachments)
|
||||
}
|
||||
if err != nil {
|
||||
accountBridge.SetError(err.Error())
|
||||
|
@ -98,6 +105,12 @@ func reply(replyid string, message string) {
|
|||
}
|
||||
}
|
||||
|
||||
func uploadAttachment(pathurl string) {
|
||||
u, _ := url.ParseRequestURI(pathurl)
|
||||
log.Println("Uploding:", u.Path)
|
||||
tc.UploadAttachment(u.Path)
|
||||
}
|
||||
|
||||
// deletePost deletes a post
|
||||
func deletePost(id string) {
|
||||
log.Println("Deleting:", id)
|
||||
|
@ -266,6 +279,7 @@ func setupMastodon(config Account) {
|
|||
|
||||
accountBridge.SetUsername("Not connected...")
|
||||
accountBridge.SetNotifications(notificationModel)
|
||||
accountBridge.SetAttachments(attachmentModel)
|
||||
accountBridge.SetConversation(conversationModel)
|
||||
accountBridge.SetAccountMessages(accountMessagesModel)
|
||||
accountBridge.SetAvatar("qrc:/qml/images/telephant_logo.png")
|
||||
|
|
Loading…
Reference in a new issue