droidlabs/motion-prime

View on GitHub
motion-prime/elements/draw/image.rb

Summary

Maintainability
B
5 hrs
Test Coverage
motion_require '../draw.rb'
module MotionPrime
  class ImageDrawElement < DrawElement
    include DrawBackgroundMixin
    attr_accessor :image_data

    def draw_options
      image = image_data || computed_options[:image]
      image ||= computed_options[:default] if computed_options[:url]

      # already initialized image or image from resources or default image
      super.merge({
        image: image.try(:uiimage),
        inner_rect: CGRectMake(frame_inner_left, frame_inner_top, frame_width, frame_height)
      })
    end

    def draw_in(rect)
      return if computed_options[:hidden]
      super
      if computed_options[:draw_in_rect]
        draw_in_context(UIGraphicsGetCurrentContext())
      else
        draw_background_in_context(UIGraphicsGetCurrentContext())
        draw_with_layer
      end
      load_image
    end

    def draw_in_context(context)
      return if computed_options[:hidden]

      draw_background_in_context(context)
      options = draw_options
      return unless image = options[:image]

      border_width = options[:border_width]
      inset = border_width > 0 ? (border_width - 1 ).abs*0.5 : 0
      rect = CGRectInset(options[:inner_rect], inset, inset)
      radius = options[:corner_radius].to_f if options[:corner_radius] && options[:masks_to_bounds]
      UIGraphicsPushContext(context)
      if radius
        draw_rect_in_context(context, rect: rect, radius: radius, rounded_corners: options[:rounded_corners])
        CGContextSaveGState(context)
        CGContextClip(context)
        image.drawInRect(rect)
        CGContextRestoreGState(context)
      else
        image.drawInRect(rect)
      end
      UIGraphicsPopContext()
    end

    def draw_with_layer
      return unless view
      options = draw_options
      @layer.try(:removeFromSuperlayer)
      return unless image = options[:image]
      rect = options[:inner_rect]

      radius = options[:corner_radius].to_f if options[:corner_radius] && options[:masks_to_bounds]

      @layer = CALayer.layer
      @layer.contents = image.CGImage
      @layer.frame = rect
      @layer.bounds = rect

      @layer.masksToBounds = options[:masks_to_bounds]
      @layer.cornerRadius = radius if radius
      view.layer.addSublayer(@layer)
    end

    def strong_references
      # .compact() is required here, otherwise screen will not be released
      refs = [section, (section.collection_section if section.respond_to?(:cell_section_name))].compact
      refs += section.strong_references if section
      refs
    end

    def load_image
      return if @loading || image_data || !computed_options[:url]
      @loading = true

      refs = strong_references
      BW::Reactor.schedule do
        return unless refs.all?(&:weakref_alive?)
        manager = SDWebImageManager.sharedManager
        manager.downloadWithURL(computed_options[:url],
          options: 0,
          progress: lambda{ |r_size, e_size|  },
          completed: lambda{ |image, error, type, finished|
            if !image || !refs.all?(&:weakref_alive?)
              @loading = false
              return
            end

            if Prime.env.development? && false
              image_cache = SDImageCache.sharedImageCache
              image_cache.clearMemory
              image_cache.clearDisk
              image_cache.cleanDisk
            end

            if computed_options[:post_process].present?
              image = computed_options[:post_process][:method].to_proc.call(computed_options[:post_process][:target], image)
            end
            self.image_data = image
            section.cached_draw_image = nil
            if section.respond_to?(:cell_section_name)
              section.pending_display!
            else
              self.view.performSelectorOnMainThread :setNeedsDisplay, withObject: nil, waitUntilDone: true
            end
            @loading = false
          }
        )
      end
    end

    def update_with_options(new_options = {})
      self.image_data = nil if new_options.slice(:url, :image).any? || new_options.blank?
      @layer.try(:removeFromSuperlayer)
      super
    end
  end
end