rubysketch-solitaire 0.1.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }