Example #1
0
 function suggestion (id) {
   var name = api.about.obs.name(id)
   return Struct({
     title: name,
     id,
     subtitle: id.substring(0, 10),
     value: computed([name, id], mention),
     image: api.about.obs.imageUrl(id),
     showBoth: true
   })
 }
Example #2
0
  function ProgressStatus (keyFn, attrs) {
    var progress = Struct(attrs || {
      pending: 0
    })

    watch(api.sbot.obs.connection, (sbot) => {
      if (sbot) {
        var source = keyFn(sbot)
        if (source) {
          pull(
            source(),
            pull.drain((event) => {
              progress.set(event)
            })
          )
        }
      }
    })

    return progress
  }
Example #3
0
  // TODO refactor this to use obs better
  function edit (id) {
    // TODO - get this to wait till the connection is present !

    var isMe = api.keys.sync.id() === id

    var avatar = Struct({
      current: api.about.obs.imageUrl(id),
      new: Dict()
    })

    const links = api.sbot.pull.links

    var name = Struct({
      current: api.about.obs.name(id),
      new: Value()
    })

    const images = computed(api.about.obs.groupedValues(id, 'image'), Object.keys)

    var namesRecord = Dict()
    // TODO constrain query to one name per peer?
    pull(
      links({dest: id, rel: 'about', values: true}),
      pull.map(e => e.value.content.name),
      pull.filter(Boolean),
      pull.drain(name => {
        var n = namesRecord.get(name) || 0
        namesRecord.put(name, n + 1)
      })
    )
    var names = dictToCollection(namesRecord)

    var publicWebHosting = Struct({
      current: api.about.obs.latestValue(id, 'publicWebHosting'),
      new: Value(api.about.obs.latestValue(id, 'publicWebHosting')())
    })

    var isPossibleUpdate = computed([name.new, avatar.new, publicWebHosting.new], (name, avatar, publicWebHostingValue) => {
      return name || avatar.link || (isMe && publicWebHostingValue !== publicWebHosting.current())
    })

    var avatarSrc = computed([avatar], avatar => {
      if (avatar.new.link) return api.blob.sync.url(avatar.new.link)
      return avatar.current
    })

    var displayedName = computed([name], name => {
      if (name.new) return name.new
      else return name.current
    })

    const modalContent = Value()
    const isOpen = Value(false)
    const modal = api.app.html.modal(modalContent, { isOpen })

    return h('AboutEditor', [
      modal,
      h('section.avatar', [
        h('section', [
          h('img', { src: avatarSrc })
        ]),
        h('footer', displayedName)
      ]),
      h('section.description', computed(api.about.obs.description(id), (descr) => {
        if (descr == null) return '' // TODO: should be in patchcore, I think...
        return api.message.html.markdown(descr)
      })),
      h('section.aliases', [
        h('header', 'Aliases'),
        h('section.avatars', [
          h('header', 'Avatars'),
          map(images, image => h('img', {
            'src': api.blob.sync.url(image),
            'ev-click': () => avatar.new.set({ link: image })
          })),
          h('div.file-upload', [
            hyperfile.asDataURL(dataUrlCallback)
          ])
        ]),
        h('section.names', [
          h('header', 'Names'),
          h('section', [
            map(names, n => h('div', { 'ev-click': () => name.new.set(n.key()) }, [
              h('div.name', n.key),
              h('div.count', n.value)
            ])),
            h('input', {
              placeholder: ' + another name',
              'ev-keyup': e => name.new.set(e.target.value)
            })
          ])
        ]),
        isMe
          ? h('section.viewer', [
            h('header', 'Public viewers'),
            h('section', [
              h('span', 'Show my posts on public viewers'),
              h('input', {
                type: 'checkbox',
                checked: publicWebHosting.current,
                'ev-change': e => publicWebHosting.new.set(e.target.checked)
              })
            ])
          ]) : '',
        when(isPossibleUpdate, h('section.action', [
          h('button.cancel', { 'ev-click': clearNewSelections }, 'cancel'),
          h('button.confirm', { 'ev-click': handleUpdateClick }, 'confirm changes')
        ]))
      ])
    ])

    function dataUrlCallback (data) {
      const cropEl = Crop(data, (err, cropData) => {
        if (err) throw err
        if (!cropData) return isOpen.set(false)

        var _data = dataurl.parse(cropData)
        api.sbot.async.addBlob(pull.once(_data.data), (err, hash) => {
          if (err) throw err // TODO check if this is safely caught by error catcher

          avatar.new.set({
            link: hash,
            size: _data.data.length,
            type: _data.mimetype,
            width: 512,
            height: 512
          })
        })
        isOpen.set(false)
      })

      modalContent.set(cropEl)
      isOpen.set(true)
    }

    function Crop (data, cb) {
      var img = h('img', { src: data })

      var crop = Value()

      waitForImg()

      return h('div.cropper', [
        crop,
        h('div.background')
      ])

      function waitForImg () {
        // WEIRDNESS - if you invoke hypecrop before img is ready,
        // the canvas instantiates and draws nothing

        if (!img.height && !img.width) {
          return window.setTimeout(waitForImg, 100)
        }

        var canvas = hypercrop(img)
        crop.set(
          h('PatchProfileCrop', [
            h('header', 'click and drag to crop your image'),
            canvas,
            h('section.actions', [
              h('button', { 'ev-click': () => cb() }, 'Cancel'),
              h('button -primary', { 'ev-click': () => cb(null, canvas.selection.toDataURL()) }, 'Okay')
            ])
          ])
        )
      }
    }

    function clearNewSelections () {
      name.new.set(null)
      avatar.new.set({})
      publicWebHosting.new.set(publicWebHosting.current())
    }

    function handleUpdateClick () {
      const newName = name.new()
      const newAvatar = avatar.new()

      const msg = {
        type: 'about',
        about: id
      }

      if (newName) msg.name = newName
      if (newAvatar.link) msg.image = newAvatar
      if (publicWebHosting.new() !== publicWebHosting.current()) msg.publicWebHosting = publicWebHosting.new()

      api.message.html.confirm(msg, (err, data) => {
        if (err) return console.error(err)

        clearNewSelections()

        // TODO - update aliases displayed
      })
    }
  }