rubysketch-solitaire 0.1.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +3 -0
  3. data/.gitignore +2 -0
  4. data/.hooks/post-commit +37 -0
  5. data/.hooks/pre-commit +69 -0
  6. data/ChangeLog.md +27 -0
  7. data/Gemfile.lock +10 -10
  8. data/Podfile.lock +33 -33
  9. data/README.md +8 -0
  10. data/Rakefile +107 -10
  11. data/RubySolitaire/Ad.swift +88 -0
  12. data/RubySolitaire/Assets.xcassets/AppIcon.appiconset/AppIcon.png +0 -0
  13. data/RubySolitaire/Assets.xcassets/AppIcon.appiconset/Contents.json +3 -87
  14. data/RubySolitaire/Base.lproj/Localizable.strings +6 -0
  15. data/RubySolitaire/Extensions.swift +5 -0
  16. data/RubySolitaire/GameView.swift +75 -13
  17. data/RubySolitaire/Helper.swift +70 -0
  18. data/RubySolitaire/MenuScreen.swift +141 -0
  19. data/RubySolitaire/RubySolitaireApp.swift +188 -1
  20. data/RubySolitaire/SafariView.swift +16 -0
  21. data/RubySolitaire/Strings.swift +48 -0
  22. data/RubySolitaire/ja.lproj/InfoPlist.strings +4 -0
  23. data/RubySolitaire/ja.lproj/Localizable.strings +6 -0
  24. data/VERSION +1 -1
  25. data/data/card.png +0 -0
  26. data/data/classicPSPWave.glsl +94 -0
  27. data/data/colorfulUnderwaterBubbles2.glsl +113 -0
  28. data/data/cosmic2.glsl +121 -0
  29. data/data/reflectiveHexes.glsl +219 -0
  30. data/fastlane/Fastfile +76 -0
  31. data/fastlane/metadata/copyright.txt +1 -0
  32. data/fastlane/metadata/en-US/apple_tv_privacy_policy.txt +1 -0
  33. data/fastlane/metadata/en-US/description.txt +5 -0
  34. data/fastlane/metadata/en-US/keywords.txt +1 -0
  35. data/fastlane/metadata/en-US/marketing_url.txt +1 -0
  36. data/fastlane/metadata/en-US/name.txt +1 -0
  37. data/fastlane/metadata/en-US/privacy_url.txt +1 -0
  38. data/fastlane/metadata/en-US/promotional_text.txt +1 -0
  39. data/fastlane/metadata/en-US/release_notes.txt +1 -0
  40. data/fastlane/metadata/en-US/subtitle.txt +1 -0
  41. data/fastlane/metadata/en-US/support_url.txt +1 -0
  42. data/fastlane/metadata/ja/apple_tv_privacy_policy.txt +1 -0
  43. data/fastlane/metadata/ja/description.txt +5 -0
  44. data/fastlane/metadata/ja/keywords.txt +1 -0
  45. data/fastlane/metadata/ja/marketing_url.txt +1 -0
  46. data/fastlane/metadata/ja/name.txt +1 -0
  47. data/fastlane/metadata/ja/privacy_url.txt +1 -0
  48. data/fastlane/metadata/ja/promotional_text.txt +1 -0
  49. data/fastlane/metadata/ja/release_notes.txt +1 -0
  50. data/fastlane/metadata/ja/subtitle.txt +1 -0
  51. data/fastlane/metadata/ja/support_url.txt +1 -0
  52. data/fastlane/metadata/primary_category.txt +1 -0
  53. data/fastlane/metadata/primary_first_sub_category.txt +1 -0
  54. data/fastlane/metadata/primary_second_sub_category.txt +1 -0
  55. data/fastlane/metadata/review_information/demo_password.txt +1 -0
  56. data/fastlane/metadata/review_information/demo_user.txt +1 -0
  57. data/fastlane/metadata/review_information/email_address.txt +1 -0
  58. data/fastlane/metadata/review_information/first_name.txt +0 -0
  59. data/fastlane/metadata/review_information/last_name.txt +0 -0
  60. data/fastlane/metadata/review_information/notes.txt +1 -0
  61. data/fastlane/metadata/review_information/phone_number.txt +0 -0
  62. data/fastlane/metadata/secondary_category.txt +1 -0
  63. data/fastlane/metadata/secondary_first_sub_category.txt +1 -0
  64. data/fastlane/metadata/secondary_second_sub_category.txt +1 -0
  65. data/lib/rubysketch/solitaire/background.rb +115 -12
  66. data/lib/rubysketch/solitaire/card.rb +10 -87
  67. data/lib/rubysketch/solitaire/common/animation.rb +34 -34
  68. data/lib/rubysketch/solitaire/common/button.rb +49 -19
  69. data/lib/rubysketch/solitaire/common/dialog.rb +78 -21
  70. data/lib/rubysketch/solitaire/common/scene.rb +15 -4
  71. data/lib/rubysketch/solitaire/common/settings.rb +15 -3
  72. data/lib/rubysketch/solitaire/common/timer.rb +2 -2
  73. data/lib/rubysketch/solitaire/common/transitions.rb +12 -6
  74. data/lib/rubysketch/solitaire/common/utils.rb +15 -0
  75. data/lib/rubysketch/solitaire/klondike.rb +382 -81
  76. data/lib/rubysketch/solitaire/places.rb +12 -102
  77. data/lib/rubysketch/solitaire/skin.rb +151 -0
  78. data/lib/rubysketch/solitaire.rb +33 -9
  79. data/main.rb +1 -0
  80. data/project.yml +85 -4
  81. metadata +55 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 81277cc0d2fd26e1236aead267584a337b431602a1f5447a9576e391864c6d72
4
- data.tar.gz: 50ffd854120be92e95ae9508edacc2fc9ab0e9eab5df23012bceea281dc54616
3
+ metadata.gz: ef707133db84935262b66e602ba0a645c8fc5570bbba72551e62080c07272859
4
+ data.tar.gz: 86db8fa959c1fc19a870ea73a9f75eeb0050525fd9565335c2150f6e475f5e27
5
5
  SHA512:
6
- metadata.gz: 704feade59169093f22fba8e0bd20b3eb950ac95b5b656bd71a0f6ddba9271f011fcbda38771d32b3d015043a3bf26976c3863cb3979011e97a6f8414b42c3ad
7
- data.tar.gz: 5cd925393288fabfaab9837cb418a288793d07d09d9e315abf95af14875779bae70d9b121f0c04600a180fddb0775d9f0f874e2dee30ea851b59d48e1f62d1c3
6
+ metadata.gz: e3f2b2f9c834e732f73697ea2a525db3c43b6eade20cc548795e53df1a00456f69e42a7863ad6c68e993834b5aec472d215573f003aa439ced91099fa3fc1ac0
7
+ data.tar.gz: f400944134b3969d67a10b1f36a2ec95b4f3b2101b134cca3f851e7603254bd396d2038800a28f9287c7b8f51f0d0f7624afbe8ae0da36fb0428922c4883f9a9
@@ -19,5 +19,8 @@ jobs:
19
19
  - name: checkout
20
20
  uses: actions/checkout@v2
21
21
 
22
+ - name: setup dependencies
23
+ run: "ruby -I.github/workflows -rutils -e 'setup_dependencies'"
24
+
22
25
  - name: build
23
26
  run: rake build
data/.gitignore CHANGED
@@ -3,6 +3,8 @@
3
3
  */Info.plist
4
4
  *~
5
5
 
6
+ config.yml
7
+ GoogleService-Info.plist
6
8
  rubysketch-solitaire-*.gem
7
9
  solitaire.json
8
10
 
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/ruby
2
+
3
+
4
+ def versions()
5
+ File.read(File.expand_path '../../ChangeLog.md', __dir__)
6
+ .split(/^\s*##\s*\[\s*v([\d\.]+)\s*\].*$/)
7
+ .slice(1..-1)
8
+ .each_slice(2)
9
+ .to_h
10
+ .transform_values do |changes|
11
+ changes.strip.lines
12
+ .group_by {|line| line[/^\W*(\[\w{2}\])/, 1]}
13
+ .map {|lang, lines|
14
+ [
15
+ lang[/\w+/],
16
+ lines.map {|line| line.sub(lang, '')}.join
17
+ ]
18
+ }
19
+ .to_h
20
+ end
21
+ end
22
+
23
+
24
+ begin
25
+ ver = File.read(File.expand_path '../../VERSION', __dir__)[/[\d\.]+/]
26
+ changes = versions[ver].dig 'en'
27
+ tag = "v#{ver}"
28
+ tags = `git tag`.lines chomp: true
29
+
30
+ raise "no version found" unless ver
31
+ return if tags.include?(tag)
32
+
33
+ raise "no changes found" unless changes
34
+
35
+ puts "Tag '#{tag}'\n#{changes}"
36
+ `git tag -a -m "#{changes}" #{tag}`
37
+ end
data/.hooks/pre-commit ADDED
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/ruby
2
+
3
+
4
+ def filter_file(path, git_add: true, &block)
5
+ File.write path, block.call(File.read path)
6
+ `git add '#{path}'` if git_add
7
+ end
8
+
9
+ def ls_files(regexp)
10
+ `git ls-files`
11
+ .lines(chomp: true)
12
+ .select {|path| path =~ regexp}
13
+ end
14
+
15
+ def versions()
16
+ File.read(File.expand_path '../../ChangeLog.md', __dir__)
17
+ .split(/^\s*##\s*\[\s*v([\d\.]+)\s*\].*$/)
18
+ .slice(1..-1)
19
+ .each_slice(2)
20
+ .to_h
21
+ .transform_values do |changes|
22
+ changes.strip.lines
23
+ .group_by {|line| line[/^\W*(\[\w{2}\])/, 1]}
24
+ .map {|lang, lines|
25
+ [
26
+ lang[/\w+/],
27
+ lines.map {|line| line.sub(lang, '')}.join
28
+ ]
29
+ }
30
+ .to_h
31
+ end
32
+ end
33
+
34
+
35
+ %w[config.yml GoogleService-Info.plist].each do |name|
36
+ raise "Do not commit #{name}" unless ls_files(/#{Regexp.escape name}/).empty?
37
+ end
38
+
39
+
40
+ begin
41
+ filter_file File.expand_path('../../VERSION', __dir__) do
42
+ versions.keys.first
43
+ end
44
+ end
45
+
46
+ begin
47
+ filter_file File.expand_path('../../project.yml', __dir__) do |body|
48
+ ver = versions.keys.first
49
+ marketing_ver = ver.split('.')
50
+ .map(&:to_i)
51
+ .tap {|a| a.pop while a.size > 3}
52
+ .join '.'
53
+ replace = -> s, key, ver {s.gsub /#{key}:\s*[\d\.]+/, "#{key}: #{ver}"}
54
+
55
+ body = replace.call body, 'CURRENT_PROJECT_VERSION', ver
56
+ body = replace.call body, 'MARKETING_VERSION', marketing_ver
57
+ end
58
+ end
59
+
60
+ begin
61
+ versions.values.first.tap do |changes|
62
+ changes.each do |lang, lines|
63
+ Dir.chdir File.expand_path('../..', __dir__) do
64
+ path = Dir.glob("fastlane/metadata/#{lang}*/release_notes.txt").first
65
+ filter_file(path) {lines}
66
+ end
67
+ end
68
+ end
69
+ end
data/ChangeLog.md ADDED
@@ -0,0 +1,27 @@
1
+ # RubySolitaire ChangeLog
2
+
3
+
4
+ ## [v0.9.0] - 2023-06-20
5
+
6
+ - [en]First beta version
7
+ - [ja]最初のベータバージョン
8
+
9
+
10
+ ## [v0.1.2] - 2023-06-16
11
+
12
+ - [en]Fixed some minor bugs
13
+ - [ja]軽微な不具合をいくつか修正
14
+
15
+
16
+ ## [v0.1.1] - 2023-06-16
17
+
18
+ - [en]Added several types of backgrounds
19
+ - [en]Fixed some minor bugs
20
+ - [ja]背景の種類をいくつか追加
21
+ - [ja]軽微な不具合をいくつか修正
22
+
23
+
24
+ ## [v0.1.0] - 2023-06-12
25
+
26
+ - [en]First stable version
27
+ - [ja]最初の安定バージョン
data/Gemfile.lock CHANGED
@@ -16,17 +16,17 @@ GEM
16
16
  artifactory (3.0.15)
17
17
  atomos (0.1.3)
18
18
  aws-eventstream (1.2.0)
19
- aws-partitions (1.771.0)
20
- aws-sdk-core (3.173.1)
19
+ aws-partitions (1.777.0)
20
+ aws-sdk-core (3.174.0)
21
21
  aws-eventstream (~> 1, >= 1.0.2)
22
22
  aws-partitions (~> 1, >= 1.651.0)
23
23
  aws-sigv4 (~> 1.5)
24
24
  jmespath (~> 1, >= 1.6.1)
25
- aws-sdk-kms (1.64.0)
26
- aws-sdk-core (~> 3, >= 3.165.0)
25
+ aws-sdk-kms (1.66.0)
26
+ aws-sdk-core (~> 3, >= 3.174.0)
27
27
  aws-sigv4 (~> 1.1)
28
- aws-sdk-s3 (1.122.0)
29
- aws-sdk-core (~> 3, >= 3.165.0)
28
+ aws-sdk-s3 (1.123.1)
29
+ aws-sdk-core (~> 3, >= 3.174.0)
30
30
  aws-sdk-kms (~> 1)
31
31
  aws-sigv4 (~> 1.4)
32
32
  aws-sigv4 (1.5.2)
@@ -85,7 +85,7 @@ GEM
85
85
  escape (0.0.4)
86
86
  ethon (0.16.0)
87
87
  ffi (>= 1.15.0)
88
- excon (0.99.0)
88
+ excon (0.100.0)
89
89
  faraday (1.10.3)
90
90
  faraday-em_http (~> 1.0)
91
91
  faraday-em_synchrony (~> 1.0)
@@ -158,7 +158,7 @@ GEM
158
158
  fourflusher (2.3.1)
159
159
  fuzzy_match (2.0.4)
160
160
  gh_inspector (1.1.3)
161
- google-apis-androidpublisher_v3 (0.42.0)
161
+ google-apis-androidpublisher_v3 (0.43.0)
162
162
  google-apis-core (>= 0.11.0, < 2.a)
163
163
  google-apis-core (0.11.0)
164
164
  addressable (~> 2.5, >= 2.5.1)
@@ -200,11 +200,11 @@ GEM
200
200
  http-cookie (1.0.5)
201
201
  domain_name (~> 0.5)
202
202
  httpclient (2.8.3)
203
- i18n (1.13.0)
203
+ i18n (1.14.1)
204
204
  concurrent-ruby (~> 1.0)
205
205
  jmespath (1.6.2)
206
206
  json (2.6.3)
207
- jwt (2.7.0)
207
+ jwt (2.7.1)
208
208
  memoist (0.16.2)
209
209
  mini_magick (4.12.0)
210
210
  mini_mime (1.1.2)
data/Podfile.lock CHANGED
@@ -1,36 +1,36 @@
1
1
  PODS:
2
2
  - CRuby (3.2.202)
3
- - RubySketch (0.5.12):
4
- - RubySketch/Beeps (= 0.5.12)
5
- - RubySketch/Rays (= 0.5.12)
6
- - RubySketch/Reflex (= 0.5.12)
7
- - RubySketch/Rucy (= 0.5.12)
8
- - RubySketch/Xot (= 0.5.12)
9
- - RubySketch/Beeps (0.5.12):
10
- - RubySketch/Beeps/Ext (= 0.5.12)
11
- - RubySketch/Beeps/R8BrainFreeSrc (= 0.5.12)
12
- - RubySketch/Beeps/STK (= 0.5.12)
13
- - RubySketch/Beeps/Ext (0.5.12)
14
- - RubySketch/Beeps/R8BrainFreeSrc (0.5.12)
15
- - RubySketch/Beeps/STK (0.5.12)
16
- - RubySketch/Rays (0.5.12):
17
- - RubySketch/Rays/Clipper (= 0.5.12)
18
- - RubySketch/Rays/Ext (= 0.5.12)
19
- - RubySketch/Rays/Poly2Tri (= 0.5.12)
20
- - RubySketch/Rays/SplineLib (= 0.5.12)
21
- - RubySketch/Rays/Clipper (0.5.12)
22
- - RubySketch/Rays/Ext (0.5.12)
23
- - RubySketch/Rays/Poly2Tri (0.5.12)
24
- - RubySketch/Rays/SplineLib (0.5.12)
25
- - RubySketch/Reflex (0.5.12):
26
- - RubySketch/Reflex/Box2D (= 0.5.12)
27
- - RubySketch/Reflex/Ext (= 0.5.12)
28
- - RubySketch/Reflex/Box2D (0.5.12)
29
- - RubySketch/Reflex/Ext (0.5.12)
30
- - RubySketch/Rucy (0.5.12):
31
- - RubySketch/Rucy/Ext (= 0.5.12)
32
- - RubySketch/Rucy/Ext (0.5.12)
33
- - RubySketch/Xot (0.5.12)
3
+ - RubySketch (0.5.17):
4
+ - RubySketch/Beeps (= 0.5.17)
5
+ - RubySketch/Rays (= 0.5.17)
6
+ - RubySketch/Reflex (= 0.5.17)
7
+ - RubySketch/Rucy (= 0.5.17)
8
+ - RubySketch/Xot (= 0.5.17)
9
+ - RubySketch/Beeps (0.5.17):
10
+ - RubySketch/Beeps/Ext (= 0.5.17)
11
+ - RubySketch/Beeps/R8BrainFreeSrc (= 0.5.17)
12
+ - RubySketch/Beeps/STK (= 0.5.17)
13
+ - RubySketch/Beeps/Ext (0.5.17)
14
+ - RubySketch/Beeps/R8BrainFreeSrc (0.5.17)
15
+ - RubySketch/Beeps/STK (0.5.17)
16
+ - RubySketch/Rays (0.5.17):
17
+ - RubySketch/Rays/Clipper (= 0.5.17)
18
+ - RubySketch/Rays/Ext (= 0.5.17)
19
+ - RubySketch/Rays/Poly2Tri (= 0.5.17)
20
+ - RubySketch/Rays/SplineLib (= 0.5.17)
21
+ - RubySketch/Rays/Clipper (0.5.17)
22
+ - RubySketch/Rays/Ext (0.5.17)
23
+ - RubySketch/Rays/Poly2Tri (0.5.17)
24
+ - RubySketch/Rays/SplineLib (0.5.17)
25
+ - RubySketch/Reflex (0.5.17):
26
+ - RubySketch/Reflex/Box2D (= 0.5.17)
27
+ - RubySketch/Reflex/Ext (= 0.5.17)
28
+ - RubySketch/Reflex/Box2D (0.5.17)
29
+ - RubySketch/Reflex/Ext (0.5.17)
30
+ - RubySketch/Rucy (0.5.17):
31
+ - RubySketch/Rucy/Ext (= 0.5.17)
32
+ - RubySketch/Rucy/Ext (0.5.17)
33
+ - RubySketch/Xot (0.5.17)
34
34
 
35
35
  DEPENDENCIES:
36
36
  - CRuby (from `https://github.com/xord/cruby.git`)
@@ -47,12 +47,12 @@ CHECKOUT OPTIONS:
47
47
  :commit: 133060a967e6acbf4aad3971b369acab86029065
48
48
  :git: https://github.com/xord/cruby.git
49
49
  RubySketch:
50
- :commit: e3abcf7e652a328a76e54ab0d1fa601bc7f1a43f
50
+ :commit: 028cabc83f0038273a599d8f021e5b0ec2819d62
51
51
  :git: https://github.com/xord/rubysketch.git
52
52
 
53
53
  SPEC CHECKSUMS:
54
54
  CRuby: f677262f16d7c714efd3021c90246296cf5bf9c3
55
- RubySketch: 76a0f9a7aff07b74bbfe2d715322607e29eac971
55
+ RubySketch: e933f316c15eb038c378894b6851e553fe08d7db
56
56
 
57
57
  PODFILE CHECKSUM: 3ad0b358d0bc13ea451aa93df078142a38c591fc
58
58
 
data/README.md CHANGED
@@ -16,6 +16,14 @@
16
16
  $ ruby -rrubysketch/solitaire -e ''
17
17
  ```
18
18
 
19
+ ## How to release to AppStore
20
+
21
+ ### Upload to TestFlight on local macOS
22
+
23
+ 1. Edit ChangeLog.md and commit
24
+ 2. Make sure you have a config.yml file
25
+ 3. run "rake release:testflight"
26
+
19
27
  ## License
20
28
 
21
29
  see [LICENSE](LICENSE) file
data/Rakefile CHANGED
@@ -5,6 +5,8 @@
5
5
  .map {|s| File.expand_path "#{s}/lib", __dir__}
6
6
  .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
7
7
 
8
+ require 'yaml'
9
+ require 'base64'
8
10
  require 'xot/rake'
9
11
 
10
12
  require 'xot/extension'
@@ -15,18 +17,48 @@ EXTENSIONS = [RubySketch::Solitaire]
15
17
 
16
18
  GEMNAME = "rubysketch-#{target.name.downcase}"
17
19
 
18
- NAME_IOS = "Ruby#{target.name}"
19
- XCWORKSPACE = "#{NAME_IOS}.xcworkspace"
20
- XCODEPROJ = "#{NAME_IOS}.xcodeproj"
20
+ PROJECT = 'project.yml'
21
+ CHANGELOG = 'ChangeLog.md'
22
+
23
+ APP_NAME = ENV['APP_NAME'] = "Ruby#{target.name}"
24
+ APP_ID = ENV['APP_ID'] = "org.xord.#{APP_NAME}"
25
+ XCWORKSPACE = "#{APP_NAME}.xcworkspace"
26
+ XCODEPROJ = "#{APP_NAME}.xcodeproj"
27
+ GINFO_PLIST = 'RubySolitaire/GoogleService-Info.plist'
21
28
 
22
29
  BUNDLE_DIR = 'vendor/bundle'
23
30
  PODS_DIR = 'Pods'
24
31
 
25
32
 
33
+ def config(key)
34
+ $config ||= YAML.load_file(File.expand_path 'config.yml', __dir__) rescue {}
35
+ key = key.to_s.upcase
36
+ ENV[key] or $config[key]
37
+ end
38
+
39
+ def versions()
40
+ File.read(CHANGELOG)
41
+ .split(/^\s*##\s*\[\s*v([\d\.]+)\s*\].*$/)
42
+ .slice(1..-1)
43
+ .each_slice(2)
44
+ .to_h
45
+ .transform_values do |changes|
46
+ changes.strip.lines
47
+ .group_by {|line| line[/^\W*(\[\w{2}\])/, 1]}
48
+ .map {|lang, lines|
49
+ [
50
+ lang[/\w+/],
51
+ lines.map {|line| line.sub(lang, '')}.join
52
+ ]
53
+ }
54
+ .to_h
55
+ end
56
+ end
57
+
58
+
26
59
  default_tasks
27
60
  build_ruby_gem
28
61
 
29
-
30
62
  task :build => 'xcode:build'
31
63
 
32
64
  task :xcode => 'xcode:open'
@@ -49,8 +81,8 @@ namespace :xcode do
49
81
  sh %( xcodebuild clean ) if File.exist?(XCODEPROJ)
50
82
  end
51
83
 
52
- task :clobber => 'xcode:clean' do
53
- sh %( rm -rf #{XCWORKSPACE} #{XCODEPROJ} )
84
+ task :clobber do
85
+ sh %( rm -rf #{XCWORKSPACE} #{XCODEPROJ} #{GINFO_PLIST} )
54
86
  end
55
87
 
56
88
  task :build => XCWORKSPACE do
@@ -63,10 +95,14 @@ namespace :xcode do
63
95
 
64
96
  file XCWORKSPACE => [BUNDLE_DIR, PODS_DIR]
65
97
 
66
- file XCODEPROJ do
98
+ file XCODEPROJ => 'scripts:setup' do
99
+ plist = config(:ginfo_plist)&.then {|s| Base64.decode64 s}
100
+ File.write GINFO_PLIST, plist if plist
101
+
67
102
  sh %( xcodegen generate )
103
+ sh %( fastlane setup_code_signing )
68
104
  end
69
- end
105
+ end# xcode
70
106
 
71
107
 
72
108
  namespace :bundle do
@@ -82,7 +118,7 @@ namespace :bundle do
82
118
  sh %( bundle install )
83
119
  raise "failed to bundle install" unless File.exist? BUNDLE_DIR
84
120
  end
85
- end
121
+ end# bundle
86
122
 
87
123
 
88
124
  namespace :pods do
@@ -97,4 +133,65 @@ namespace :pods do
97
133
  file PODS_DIR => [BUNDLE_DIR, XCODEPROJ] do
98
134
  sh %( bundle exec pod install --verbose --repo-update )
99
135
  end
100
- end
136
+ end# pods
137
+
138
+
139
+ namespace :release do
140
+ task :testflight => 'release:setup' do
141
+ ENV['MATCH_TYPE'] = 'AppStore'
142
+ sh %( fastlane setup_code_signing )
143
+
144
+ ENV['CHANGELOG'] = versions.values.first['en']
145
+ sh %( fastlane release_testflight )
146
+ end
147
+
148
+ task :setup => ['xcode:clobber', :clobber, XCWORKSPACE] do
149
+ replace = -> s, key, value {s.gsub /#{key}:\s*.+/, "#{key}: #{value}"}
150
+
151
+ filter_file PROJECT do |body|
152
+ body = replace.call(
153
+ body,
154
+ 'GADApplicationIdentifier',
155
+ config(:gad_app_id))
156
+ body = replace.call(
157
+ body,
158
+ 'GADGameScreenBottomBanner',
159
+ config(:gad_game_screen_bottom_banner))
160
+ body = replace.call(
161
+ body,
162
+ 'GADGameScreenInterstitial',
163
+ config(:gad_game_screen_interstitial))
164
+ end
165
+ end
166
+
167
+ namespace :match do
168
+ task(:update) {sh %( fastlane match_update )}
169
+ task(:fetch) {sh %( fastlane match_fetch )}
170
+ task(:delete) {sh %( fastlane match_delete )}
171
+
172
+ task :refresh => ['fastlane:match:delete', 'fastlane:match:update']
173
+
174
+ task :fetch_new_devices do
175
+ sh %( fastlane match development --force_for_new_devices )
176
+ end
177
+ end# match
178
+ end# release
179
+
180
+
181
+ namespace :scripts do
182
+ task :setup => 'scripts:hooks:setup'
183
+
184
+ namespace :hooks do
185
+ hooks = Dir.glob('.hooks/*')
186
+ .map {|path| [path, ".git/hooks/#{File.basename path}"]}
187
+ .to_h
188
+
189
+ task :setup => hooks.values
190
+
191
+ hooks.each do |from, to|
192
+ file to => from do
193
+ sh %( cp #{from} #{to} )
194
+ end
195
+ end
196
+ end
197
+ end# scripts
@@ -0,0 +1,88 @@
1
+ import SwiftUI
2
+ import GoogleMobileAds
3
+
4
+
5
+ struct AdBannerView: UIViewRepresentable {
6
+ let width: Double
7
+ let adUnitID: String
8
+ let rootViewController: UIViewController
9
+
10
+ func makeUIView(context: Context) -> some UIView {
11
+ let view = GADBannerView(adSize: GADPortraitAnchoredAdaptiveBannerAdSizeWithWidth(width))
12
+ view.adUnitID = adUnitID
13
+ view.rootViewController = rootViewController
14
+ view.load(GADRequest())
15
+ return view
16
+ }
17
+
18
+ func updateUIView(_ uiView: UIViewType, context: Context) {
19
+ }
20
+ }
21
+
22
+
23
+ class InterstitialAd: NSObject, GADFullScreenContentDelegate, ObservableObject {
24
+
25
+ let adUnitID: String
26
+
27
+ @Published var ready = false
28
+
29
+ private var ad: GADInterstitialAd? {
30
+ didSet {
31
+ ready = ad != nil
32
+ }
33
+ }
34
+
35
+ private var closed: ((Error?) -> Void)?
36
+
37
+ init(adUnitID: String) {
38
+ self.adUnitID = adUnitID
39
+ super.init()
40
+ load()
41
+ }
42
+
43
+ func load() {
44
+ if ad != nil {
45
+ return
46
+ }
47
+ GADInterstitialAd.load(withAdUnitID: adUnitID, request: GADRequest()) { [weak self] ad, error in
48
+ guard error == nil, let self = self else {
49
+ print("Failed to load interstitial ad: \(error?.localizedDescription ?? "Unknown")")
50
+ return
51
+ }
52
+
53
+ self.ad = ad
54
+ self.ad?.fullScreenContentDelegate = self
55
+ }
56
+ }
57
+
58
+ func show(rootViewController: UIViewController, closed: @escaping (Error?) -> Void) {
59
+ guard let ad = ad else {
60
+ closed(InterstitialAdCancelError())
61
+ return load()
62
+ }
63
+
64
+ self.closed = closed
65
+ ad.present(fromRootViewController: rootViewController)
66
+ }
67
+
68
+ func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
69
+ self.ad = nil
70
+ load()
71
+ if let closed = self.closed {
72
+ closed(nil)
73
+ self.closed = nil
74
+ }
75
+ }
76
+
77
+ func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
78
+ self.ad = nil
79
+ load()
80
+ if let closed = self.closed {
81
+ closed(error)
82
+ self.closed = nil
83
+ }
84
+ }
85
+ }
86
+
87
+
88
+ class InterstitialAdCancelError: Error {}
@@ -1,93 +1,9 @@
1
1
  {
2
2
  "images" : [
3
3
  {
4
- "idiom" : "iphone",
5
- "scale" : "2x",
6
- "size" : "20x20"
7
- },
8
- {
9
- "idiom" : "iphone",
10
- "scale" : "3x",
11
- "size" : "20x20"
12
- },
13
- {
14
- "idiom" : "iphone",
15
- "scale" : "2x",
16
- "size" : "29x29"
17
- },
18
- {
19
- "idiom" : "iphone",
20
- "scale" : "3x",
21
- "size" : "29x29"
22
- },
23
- {
24
- "idiom" : "iphone",
25
- "scale" : "2x",
26
- "size" : "40x40"
27
- },
28
- {
29
- "idiom" : "iphone",
30
- "scale" : "3x",
31
- "size" : "40x40"
32
- },
33
- {
34
- "idiom" : "iphone",
35
- "scale" : "2x",
36
- "size" : "60x60"
37
- },
38
- {
39
- "idiom" : "iphone",
40
- "scale" : "3x",
41
- "size" : "60x60"
42
- },
43
- {
44
- "idiom" : "ipad",
45
- "scale" : "1x",
46
- "size" : "20x20"
47
- },
48
- {
49
- "idiom" : "ipad",
50
- "scale" : "2x",
51
- "size" : "20x20"
52
- },
53
- {
54
- "idiom" : "ipad",
55
- "scale" : "1x",
56
- "size" : "29x29"
57
- },
58
- {
59
- "idiom" : "ipad",
60
- "scale" : "2x",
61
- "size" : "29x29"
62
- },
63
- {
64
- "idiom" : "ipad",
65
- "scale" : "1x",
66
- "size" : "40x40"
67
- },
68
- {
69
- "idiom" : "ipad",
70
- "scale" : "2x",
71
- "size" : "40x40"
72
- },
73
- {
74
- "idiom" : "ipad",
75
- "scale" : "1x",
76
- "size" : "76x76"
77
- },
78
- {
79
- "idiom" : "ipad",
80
- "scale" : "2x",
81
- "size" : "76x76"
82
- },
83
- {
84
- "idiom" : "ipad",
85
- "scale" : "2x",
86
- "size" : "83.5x83.5"
87
- },
88
- {
89
- "idiom" : "ios-marketing",
90
- "scale" : "1x",
4
+ "filename" : "AppIcon.png",
5
+ "idiom" : "universal",
6
+ "platform" : "ios",
91
7
  "size" : "1024x1024"
92
8
  }
93
9
  ],
@@ -0,0 +1,6 @@
1
+ appName = "RubySolitaire";
2
+
3
+ close = "Close";
4
+
5
+ menuPrivacyPolicy = "Privacy Policy";
6
+ menuLicenses = "Licenses";
@@ -0,0 +1,5 @@
1
+ extension URL: Identifiable {
2
+ public var id: String {
3
+ absoluteString
4
+ }
5
+ }