tgios 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjFlOTkxYjQ2MGRmMDAwNDE5MTZhYzBhZWI3MzQ5Y2U4NTcwOTcyYQ==
5
+ data.tar.gz: !binary |-
6
+ NGNkYThiNTU4YWUxMjc2OTQxOTkxYWFkMjFiMWIzYjkyNDQxZThhNQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MzBkZDQzYzllMjNiNGI1MzNkNTk3ZWM5ZWUyNzU4NDk1YTM4NDFlNWFiNWZh
10
+ ZmJhZGI4MGFiZDc1YWExZDcxNmQwNmRhYWQxYjE0ZjJiZjMwNzNkMzBjOGEw
11
+ MDU5MzUyZWMyZTQ5MDYxNjIxZmU1ZWIyNjg1Nzc5NmNiMGQyMzQ=
12
+ data.tar.gz: !binary |-
13
+ NDlkNDkwMGZmY2U5YWNjYmNkNzU1ZDY5ZGJiNjk3MDgxMTQyYWVmYTNlZTEw
14
+ OTliODJhMjk5NGYwNjk0YzBjMTMyODdlODZjOGM3MTAxYmU2YjBkNDc1NzNh
15
+ MjRjMzJjYTYzOWU3MGY0MzFlNDczNTEzMDljMWY0OGU1NWRlYzI=
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+
3
+ .repl_history
4
+ build
5
+ tags
6
+ app/pixate_code.rb
7
+ resources/*.nib
8
+ resources/*.momd
9
+ resources/*.storyboardc
10
+ .DS_Store
11
+ nbproject
12
+ .redcar
13
+ #*#
14
+ *~
15
+ *.sw[po]
16
+ .eprj
17
+ .sass-cache
18
+ .idea
19
+ .build
20
+ build-*
21
+ .dat*
22
+ .ruby-gemset
23
+ .ruby-version
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :test, :development do
4
+ gem 'rake'
5
+ gem 'motion-stump'
6
+ end
7
+
8
+ gemspec
9
+
10
+ #gem 'plastic_cup', '>=0.1.1'
11
+ #gem 'sugarcube', '1.1.0', require: 'sugarcube-classic'
data/Gemfile.lock ADDED
@@ -0,0 +1,26 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ tgios (0.0.1)
5
+ awesome_print_motion
6
+ motion-layout
7
+ plastic_cup (>= 0.1.1)
8
+ sugarcube (= 1.1.0)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ awesome_print_motion (0.1.0)
14
+ motion-layout (0.0.1)
15
+ motion-stump (0.3.0)
16
+ plastic_cup (0.1.1)
17
+ rake (10.1.0)
18
+ sugarcube (1.1.0)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ motion-stump
25
+ rake
26
+ tgios!
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2014, April
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ Redistributions in binary form must reproduce the above copyright notice, this
11
+ list of conditions and the following disclaimer in the documentation and/or
12
+ other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+ $:.unshift("/Library/RubyMotion/lib")
3
+ require 'motion/project/template/ios'
4
+
5
+ begin
6
+ require 'bundler'
7
+ Bundler.require
8
+ require 'motion-stump'
9
+ require 'sugarcube'
10
+ require 'plastic_cup'
11
+ require 'plastic_cup/stylesheet'
12
+ rescue LoadError
13
+ end
14
+
15
+ Motion::Project::App.setup do |app|
16
+ # Use `rake config' to see complete project settings.
17
+ app.name = 'tgios'
18
+ app.identifier = 'com.tofugear.tgios'
19
+ app.specs_dir = "spec/"
20
+ end
@@ -0,0 +1,14 @@
1
+ class AppDelegate
2
+ def application(application, didFinishLaunchingWithOptions:launchOptions)
3
+ return true if RUBYMOTION_ENV == 'test'
4
+
5
+ @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
6
+ ctlr = MyController.new
7
+ @window.rootViewController = ctlr
8
+ @window.makeKeyAndVisible
9
+ true
10
+ end
11
+
12
+ class MyController < UIViewController
13
+ end
14
+ end
@@ -0,0 +1,50 @@
1
+ module Tgios
2
+ class AnimatableView < UIView
3
+ DURATION = 0.25
4
+
5
+ def initWithFrame(frame)
6
+ super
7
+ bg_view = PlasticCup::Base.style(UIView.new,
8
+ frame: self.bounds,
9
+ backgroundColor: :white.uicolor,
10
+ alpha: 0.95)
11
+ self.addSubview(bg_view)
12
+ self
13
+ end
14
+
15
+ def show_animated
16
+ @show_notification ||= NSNotification.notificationWithName(
17
+ UIKeyboardWillShowNotification,
18
+ object: self,
19
+ userInfo:{UIKeyboardFrameEndUserInfoKey=> NSValue.valueWithCGRect(self.frame),
20
+ UIKeyboardAnimationCurveUserInfoKey=> UIViewAnimationOptionCurveEaseInOut,
21
+ UIKeyboardAnimationDurationUserInfoKey=> DURATION})
22
+ UIView.animateWithDuration(DURATION, animations: ->{
23
+ NSNotificationCenter.defaultCenter.postNotification(@show_notification)
24
+ self.alpha = 1.0
25
+ frame = self.frame
26
+ frame.origin.y = self.superview.frame.size.height - self.bounds.size.height
27
+ self.frame = frame
28
+ })
29
+ @is_shown = true
30
+ end
31
+
32
+ def hide_animated
33
+ if @is_shown
34
+ @hide_notification ||= NSNotification.notificationWithName(
35
+ UIKeyboardWillHideNotification,
36
+ object: self,
37
+ userInfo:{UIKeyboardAnimationCurveUserInfoKey=> UIViewAnimationOptionCurveEaseInOut,
38
+ UIKeyboardAnimationDurationUserInfoKey=> DURATION})
39
+ UIView.animateWithDuration(DURATION, animations: ->{
40
+ NSNotificationCenter.defaultCenter.postNotification(@hide_notification)
41
+ self.alpha = 0.0
42
+ frame = self.frame
43
+ frame.origin.y = self.superview.frame.size.height
44
+ self.frame = frame
45
+ })
46
+ @is_shown = false
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,38 @@
1
+ module Tgios
2
+ class BindingBase
3
+ def initialize(*arg)
4
+ @hook_bindings = []
5
+ end
6
+
7
+ def prepareForRelease
8
+ @hook_bindings = nil
9
+ onPrepareForRelease
10
+ end
11
+
12
+ def onPrepareForRelease
13
+ raise NotImplementedError.new("prepareForRelease not overridden for class #{self.class.name}")
14
+ end
15
+
16
+ def hook(control, event, &block)
17
+ binding=if control.is_a?(UIButton)
18
+ UIButtonBinding.new.bind(control).on(event, &block)
19
+ end
20
+
21
+ @hook_bindings << binding
22
+ binding
23
+
24
+ end
25
+
26
+ def unhook(control, event)
27
+ if control.is_a?(UIButton)
28
+ UIButtonBinding.unbind(control)
29
+ end
30
+ end
31
+
32
+ def dealloc
33
+ ap "#{self.class.name} dealloc"
34
+ super
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,30 @@
1
+
2
+ include SugarCube::CoreGraphics
3
+ module Tgios
4
+ class CommonUIUtility
5
+ def self.imageFromColor(color)
6
+
7
+ rect=Rect(0,0,1,1)
8
+ UIGraphicsBeginImageContext(rect.size)
9
+ context=UIGraphicsGetCurrentContext()
10
+ uicolor = color.is_a?(UIColor) ? color : color.uicolor
11
+ CGContextSetFillColorWithColor(context, uicolor.CGColor)
12
+ CGContextFillRect(context, rect)
13
+ image=UIGraphicsGetImageFromCurrentImageContext()
14
+ UIGraphicsEndImageContext()
15
+ image
16
+ end
17
+
18
+ def self.fix_orientation(image)
19
+ if image.imageOrientation == UIImageOrientationUp
20
+ image
21
+ else
22
+ UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
23
+ image.drawInRect([[0,0], image.size])
24
+ normalized_image = UIImage.UIGraphicsGetImageFromCurrentImageContext
25
+ UIGraphicsEndImageContext()
26
+ normalized_image
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ module Tgios
2
+ module CustomMethod
3
+ def self.included(base)
4
+ base.class_eval do
5
+ extend ClassMethods
6
+ end
7
+
8
+ end
9
+
10
+ def on(event_name, &block)
11
+ @events[event_name]=block
12
+ end
13
+
14
+ def off(*event_names)
15
+ event_names.each {|event_name| @events.delete(event_name) }
16
+ end
17
+
18
+ module ClassMethods
19
+ def define_custom_method(name=[])
20
+ name.each do |fld|
21
+ define_method fld do
22
+ self.instance_variable_get(:"@#{fld}")
23
+ end
24
+ define_method "#{fld}=" do |value|
25
+ old_value=self.instance_variable_get(:"@#{fld}")
26
+ self.instance_variable_set(:"@#{fld}", value)
27
+ @events[:value_changed].call(self, fld, old_value, value) unless @events.nil? || @events[:value_changed].nil?
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,37 @@
1
+ module Tgios
2
+ module ExtendedUITableView
3
+ include PlasticCup
4
+
5
+ def add_full_table_view_to(view)
6
+ table = Base.style(UITableView.grouped, :grouped_table)
7
+ Motion::Layout.new do |l|
8
+ l.view view
9
+ l.subviews 'table' => table
10
+ l.vertical '|[table]|'
11
+ l.horizontal '|[table]|'
12
+ end
13
+ table
14
+ end
15
+
16
+ def add_title_to_table_header(title, table)
17
+ frame = table.bounds
18
+ frame.size.height = 45
19
+ table_header = UIView.alloc.initWithFrame(frame)
20
+ table.tableHeaderView = table_header
21
+ add_title_to_view(title, table_header)
22
+
23
+ end
24
+
25
+ def add_title_to_view(title, view)
26
+
27
+ Motion::Layout.new do |l|
28
+ l.view view
29
+ l.subviews 'label' => Base.style(UILabel.new, text: title,
30
+ font: UIFont.boldSystemFontOfSize(19),
31
+ adjustsFontSizeToFitWidth: true)
32
+ l.vertical '|-10-[label]|'
33
+ l.horizontal '|-10-[label]-10-|'
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,42 @@
1
+ module Tgios
2
+ class ExtendedUIViewController < UIViewController
3
+ def viewDidLoad
4
+ super
5
+ self.edgesForExtendedLayout = UIRectEdgeNone if self.respond_to?(:edgesForExtendedLayout)
6
+ @bindings=[]
7
+ end
8
+
9
+ def prepareForRelease
10
+ @bindings=nil
11
+ onPrepareForRelease
12
+ end
13
+
14
+ def onPrepareForRelease
15
+ raise NotImplementedError.new("onPrepareForRelease not overridden for class #{self.class.name}")
16
+ end
17
+
18
+ def hook(control, event, &block)
19
+ binding=if control.is_a?(UIButton)
20
+ UIButtonBinding.new.bind(control).on(event, &block)
21
+ end
22
+
23
+ @bindings << binding
24
+ binding
25
+
26
+ end
27
+
28
+ def viewDidDisappear(animated)
29
+ if self.isMovingFromParentViewController
30
+ ap "#{self.class.name} view moving away, prepare for release"
31
+ # cut off all crap to avoid memory leak
32
+ self.prepareForRelease()
33
+ end
34
+ super
35
+ end
36
+
37
+ def dealloc
38
+ ap "#{self.class.name} dealloc"
39
+ super
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,60 @@
1
+ module Tgios
2
+ class ImageLoader < BindingBase
3
+
4
+ def initialize(url)
5
+ super
6
+ @url = url
7
+ @events = {}
8
+ end
9
+
10
+ def on(event, &block)
11
+ @events[event]=block
12
+ end
13
+
14
+ def load
15
+ image = UIImage.imageWithContentsOfFile(self.file_path)
16
+ if image.nil?
17
+ AFMotion::HTTP.get(@url) do |result|
18
+ image = UIImage.imageWithData(result.object)
19
+ @events[:image_loaded].call(image, result.success?) unless @events.nil? || @events[:image_loaded].nil?
20
+ NSFileManager.defaultManager.createFileAtPath(self.file_path, contents: result.object, attributes:nil)
21
+ end
22
+ else
23
+ @events[:image_loaded].call(image, true) unless @events.nil? || @events[:image_loaded].nil?
24
+ end
25
+ end
26
+
27
+ def self.base_path
28
+ @base_path ||= "#{NSTemporaryDirectory()}web/"
29
+ end
30
+
31
+ def filename
32
+ @filename ||= (
33
+ nsurl = NSURL.URLWithString(@url)
34
+ path = "#{nsurl.host}#{nsurl.path}"
35
+ CGI.escape(path)
36
+ )
37
+ end
38
+
39
+ def file_path
40
+ @file_path ||= (
41
+ NSFileManager.defaultManager.createDirectoryAtPath(self.class.base_path,
42
+ withIntermediateDirectories: true,
43
+ attributes: nil,
44
+ error: nil)
45
+ "#{self.class.base_path}#{self.filename}"
46
+ )
47
+ end
48
+
49
+ def self.clear_files
50
+ fm = NSFileManager.defaultManager
51
+ fm.contentsOfDirectoryAtPath(self.base_path, error:nil).each do |filename|
52
+ fm.removeItemAtPath("#{self.base_path}#{filename}", error: nil)
53
+ end
54
+ end
55
+
56
+ def onPrepareForRelease
57
+ @events = nil
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,47 @@
1
+ include PlasticCup
2
+ module Tgios
3
+ module LoadingIndicator
4
+ def add_loading_indicator_to(view)
5
+ Base.add_style_sheet(:loading_view, {
6
+ backgroundColor: :black.uicolor,
7
+ alpha: 0.5
8
+ })
9
+ @loading_view = Base.style(UIView.new, hidden: true)
10
+ base_view = Base.style(UIView.new, :loading_view)
11
+ @indicator = UIActivityIndicatorView.large
12
+ [{super_view: view, subview: @loading_view}, {super_view: @loading_view, subview: base_view}, {super_view: @loading_view, subview: @indicator}].each do |hash|
13
+ Motion::Layout.new do |l|
14
+ l.view hash[:super_view]
15
+ l.subviews 'subview' => hash[:subview]
16
+ l.vertical '|[subview]|'
17
+ l.horizontal '|[subview]|'
18
+ end
19
+ end
20
+ @label = Base.style(UILabel.new,
21
+ frame: view.bounds,
22
+ font: lambda {UIFont.systemFontOfSize(22)},
23
+ textAlignment: :center.uialignment,
24
+ backgroundColor: :clear.uicolor,
25
+ textColor: :white.uicolor)
26
+ @label.sizeToFit
27
+ Motion::Layout.new do |l|
28
+ l.view @loading_view
29
+ l.subviews 'label' => @label
30
+ l.vertical '[label]-290-|'
31
+ l.horizontal '|-20-[label]-20-|'
32
+ end
33
+ end
34
+
35
+ def start_loading(text='')
36
+ @label.text = text
37
+ self.view.endEditing(true)
38
+ @loading_view.hidden = false
39
+ @indicator.startAnimating
40
+ end
41
+
42
+ def stop_loading
43
+ @loading_view.hidden = true
44
+ @indicator.stopAnimating
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,20 @@
1
+ module Tgios
2
+ module ModelErrorsHelper
3
+ def has_error_in_fields_and_errors_for_name(fields, errors, field_name)
4
+ if errors.is_a?(Hash)
5
+ errors.has_key?(field_name) || errors.has_key?(related_name_in_fields(fields, field_name))
6
+ else
7
+ false
8
+ end
9
+ end
10
+
11
+ def related_name_in_fields(fields, field_name)
12
+ field = fields.find{|fld| fld[:name] == field_name}
13
+ if field.is_a?(Hash)
14
+ field[:related_name]
15
+ else
16
+ nil
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ module Tgios
2
+ class NSDateHelper
3
+ def self.to_nsdate(date_string)
4
+ @formatter ||= (
5
+ @formatter = NSDateFormatter.new
6
+ @formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
7
+ @formatter.timeZone = NSTimeZone.timeZoneForSecondsFromGMT(0)
8
+ @formatter
9
+ )
10
+ date = @formatter.dateFromString(date_string)
11
+ if date.nil?
12
+ @formatter2 ||= (
13
+ @formatter2 = NSDateFormatter.new
14
+ @formatter2.dateFormat = "yyyy-MM-dd HH:mm:ss"
15
+ @formatter2.timeZone = NSTimeZone.timeZoneForSecondsFromGMT(0)
16
+ @formatter2
17
+ )
18
+ date = @formatter2.dateFromString(date_string).utc
19
+
20
+ else
21
+ date.utc
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ module Tgios
2
+ class PhotoController < ExtendedUIViewController
3
+ include LoadingIndicator
4
+ attr_accessor :url
5
+
6
+ def viewDidLoad
7
+ super
8
+ self.view.backgroundColor = :black.uicolor
9
+
10
+ add_loading_indicator_to(self.view)
11
+ unless @url.nil?
12
+ start_loading
13
+ image_loader = ImageLoader.new(@url)
14
+ image_loader.on(:image_loaded) do |image, success|
15
+ stop_loading
16
+ if success
17
+ ap 'image loaded'
18
+ # TODO: use motion layout or other way to handle frame size (or allow full screen)
19
+ small_frame = self.view.bounds
20
+ small_frame.size.height -= 20 + 44 if small_frame == UIScreen.mainScreen.bounds
21
+
22
+ scroll_view = PhotoScrollView.alloc.initWithFrame(small_frame, image: image)
23
+ self.view.addSubview(scroll_view)
24
+ end
25
+ image_loader.prepareForRelease
26
+ end
27
+ image_loader.load
28
+
29
+ end
30
+ end
31
+
32
+ def onPrepareForRelease
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,61 @@
1
+ module Tgios
2
+ class PhotoScrollView < UIScrollView
3
+ MAX_SCALE = 4.0
4
+
5
+ def initWithFrame(frame, image: image)
6
+ initWithFrame(frame)
7
+ ap "init #{self.class.name}"
8
+ self.showsVerticalScrollIndicator = false
9
+ self.showsHorizontalScrollIndicator = false
10
+ self.bouncesZoom = true
11
+ self.decelerationRate = UIScrollViewDecelerationRateFast
12
+ self.delegate = self
13
+ self.backgroundColor = :clear.uicolor
14
+
15
+ page_rect = CGRectMake(0, 0, image.size.width, image.size.height)
16
+
17
+ img_scale = frame.size.width / page_rect.size.width
18
+ fit_scale = frame.size.height / page_rect.size.height
19
+ fit_scale = img_scale if img_scale < fit_scale
20
+
21
+ page_rect.size = CGSizeMake(page_rect.size.width * img_scale, page_rect.size.height * img_scale)
22
+
23
+ @image_view = PlasticCup::Base.style(UIImageView.new,
24
+ image: image,
25
+ frame: page_rect,
26
+ contentMode: UIViewContentModeScaleAspectFit)
27
+ self.addSubview(@image_view)
28
+
29
+ self.zoomScale = 0.995 if page_rect.size.height > frame.size.height
30
+
31
+ self.maximumZoomScale = MAX_SCALE / img_scale
32
+ self.minimumZoomScale = fit_scale / img_scale
33
+
34
+ self
35
+ end
36
+
37
+ def layoutSubviews
38
+ super
39
+
40
+ bsize = self.bounds.size
41
+ center_frame = @image_view.frame
42
+
43
+ center_frame.origin.x = center_frame.size.width < bsize.width ? (bsize.width - center_frame.size.width) / 2.0 : 0
44
+ center_frame.origin.y = center_frame.size.height < bsize.height ? (bsize.height - center_frame.size.height) / 2.0 : 0
45
+
46
+ @image_view.frame = center_frame
47
+ @image_view.contentScaleFactor = 1.0
48
+
49
+ end
50
+
51
+ def viewForZoomingInScrollView(scrollView)
52
+ @image_view
53
+ end
54
+
55
+ def dealloc
56
+ ap "dealloc #{self.class.name}"
57
+ super
58
+ end
59
+
60
+ end
61
+ end