├── .gitattributes ├── 9781484250303.jpg ├── Ch02 ├── 1.KV_language │ ├── main.py │ └── test.kv ├── 2.load_model │ ├── main.py │ └── test1.kv └── 3.load_string │ └── main.py ├── Ch03 ├── Flask Server │ └── FlaskServer.py └── Kivy Client │ ├── main.py │ └── pycam.kv ├── Ch04 ├── Flask Server │ └── CamShareServer.py └── Kivy Client │ ├── buildozer.spec │ ├── icon.png │ ├── logo.png │ ├── main.py │ ├── presplash.png │ └── pycam.kv ├── Ch05-06 ├── 0.png ├── 1.png ├── 10.png ├── 11.png ├── 12.png ├── 13.png ├── 14.png ├── 15.png ├── 16.png ├── 17.png ├── 2.png ├── 21.png ├── 22.png ├── 23.png ├── 24.png ├── 25.png ├── 26.png ├── 27.png ├── 28.png ├── 29.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 91.png ├── 92.png ├── 93.png ├── 94.png ├── 95.png ├── bg_cointex.png ├── buildozer.spec ├── coin.png ├── cointex_logo.png ├── cointex_presplash.png ├── fire.png ├── game_info ├── levels-bg │ ├── bg_lvl1.jpg │ ├── bg_lvl10.jpg │ ├── bg_lvl11.jpg │ ├── bg_lvl12.jpg │ ├── bg_lvl13.jpg │ ├── bg_lvl14.jpg │ ├── bg_lvl15.jpg │ ├── bg_lvl16.jpg │ ├── bg_lvl17.jpg │ ├── bg_lvl18.jpg │ ├── bg_lvl19.jpg │ ├── bg_lvl2.jpg │ ├── bg_lvl20.jpg │ ├── bg_lvl3.jpg │ ├── bg_lvl3.png │ ├── bg_lvl4.jpg │ ├── bg_lvl4.png │ ├── bg_lvl5.jpg │ ├── bg_lvl5.png │ ├── bg_lvl6.jpg │ ├── bg_lvl6.png │ ├── bg_lvl7.jpg │ ├── bg_lvl8.jpg │ └── bg_lvl9.jpg ├── levels-images │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ ├── 2.png │ ├── 20.png │ ├── 21.png │ ├── 22.png │ ├── 23.png │ ├── 24.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ └── 9.png ├── main.py ├── music │ ├── bg_music_piano.wav │ ├── bg_music_piano_flute.wav │ ├── char_death_flaute.wav │ ├── coin.wav │ └── level_completed_flaute.wav ├── other-images │ ├── About-Us.png │ ├── Congratulations-Passed.png │ └── Main-Screen.png └── test.kv ├── Ch07 └── 1.AudioApp │ ├── audio.kv │ ├── bg_music_piano.wav │ ├── buildozer.spec │ ├── icon.png │ ├── main.py │ └── presplash.png ├── Contributing.md ├── LICENSE.txt ├── README.md └── errata.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /9781484250303.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/9781484250303.jpg -------------------------------------------------------------------------------- /Ch02/1.KV_language/main.py: -------------------------------------------------------------------------------- 1 | import kivy.app 2 | 3 | class TestApp(kivy.app.App): 4 | 5 | def button1_press(self): 6 | self.root.ids['text_label'].text = self.root.ids['text_input1'].text 7 | 8 | def button2_press(self): 9 | self.root.ids['text_label'].text = self.root.ids['text_input2'].text 10 | 11 | app = TestApp() 12 | app.run() 13 | -------------------------------------------------------------------------------- /Ch02/1.KV_language/test.kv: -------------------------------------------------------------------------------- 1 | BoxLayout: 2 | orientation: "vertical" 3 | Label: 4 | text: "Waiting for Button Press" 5 | id: text_label 6 | BoxLayout: 7 | orientation: "horizontal" 8 | TextInput: 9 | text: "TextInput 1" 10 | id: text_input1 11 | Button: 12 | text: "Click me" 13 | on_press: app.button1_press() 14 | BoxLayout: 15 | orientation: "horizontal" 16 | TextInput: 17 | text: "TextInput 2" 18 | id: text_input2 19 | Button: 20 | text: "Click me" 21 | on_press: app.button2_press() 22 | -------------------------------------------------------------------------------- /Ch02/2.load_model/main.py: -------------------------------------------------------------------------------- 1 | import kivy.app 2 | import kivy.lang 3 | 4 | class TestApp(kivy.app.App): 5 | 6 | def button1_press(self): 7 | self.root.ids['text_label'].text = self.root.ids['text_input1'].text 8 | 9 | def button2_press(self): 10 | self.root.ids['text_label'].text = self.root.ids['text_input2'].text 11 | 12 | def build(self): 13 | return kivy.lang.Builder.load_file("test1.kv") 14 | 15 | app = TestApp() 16 | app.run() 17 | -------------------------------------------------------------------------------- /Ch02/2.load_model/test1.kv: -------------------------------------------------------------------------------- 1 | BoxLayout: 2 | orientation: "vertical" 3 | Label: 4 | text: "Waiting for Button Press" 5 | id: text_label 6 | BoxLayout: 7 | orientation: "horizontal" 8 | TextInput: 9 | text: "TextInput 1" 10 | id: text_input1 11 | Button: 12 | text: "Click me" 13 | on_press: app.button1_press() 14 | BoxLayout: 15 | orientation: "horizontal" 16 | TextInput: 17 | text: "TextInput 2" 18 | id: text_input2 19 | Button: 20 | text: "Click me" 21 | on_press: app.button2_press() 22 | -------------------------------------------------------------------------------- /Ch02/3.load_string/main.py: -------------------------------------------------------------------------------- 1 | import kivy.app 2 | import kivy.lang 3 | 4 | class TestApp(kivy.app.App): 5 | 6 | def button1_press(self): 7 | self.root.ids['text_label'].text = self.root.ids['text_input1'].text 8 | 9 | def button2_press(self): 10 | self.root.ids['text_label'].text = self.root.ids['text_input2'].text 11 | 12 | def build(self): 13 | return kivy.lang.Builder.load_string( 14 | """ 15 | BoxLayout: 16 | orientation: "vertical" 17 | Label: 18 | text: "Waiting for Button Press" 19 | id: text_label 20 | BoxLayout: 21 | orientation: "horizontal" 22 | TextInput: 23 | text: "TextInput 1" 24 | id: text_input1 25 | Button: 26 | text: "Click me" 27 | on_press: app.button1_press() 28 | BoxLayout: 29 | orientation: "horizontal" 30 | TextInput: 31 | text: "TextInput 2" 32 | id: text_input2 33 | Button: 34 | text: "Click me" 35 | on_press: app.button2_press() 36 | """) 37 | 38 | app = TestApp() 39 | app.run() 40 | -------------------------------------------------------------------------------- /Ch03/Flask Server/FlaskServer.py: -------------------------------------------------------------------------------- 1 | import flask 2 | import base64 3 | import PIL.Image 4 | import webbrowser 5 | import os 6 | 7 | app = flask.Flask(import_name="FlaskUpload") 8 | 9 | cam_width = 0 10 | cam_height = 0 11 | 12 | html_opened = False 13 | 14 | @app.route('/camSize', methods = ['GET', 'POST']) 15 | def cam_size(): 16 | global cam_width 17 | global cam_height 18 | 19 | cam_width = int(float(flask.request.args["width"])) 20 | cam_height = int(float(flask.request.args["height"])) 21 | 22 | print('Width',cam_width,'& Height',cam_height,'Received Successfully.') 23 | 24 | return "OK" 25 | 26 | @app.route('/', methods = ['POST']) 27 | def upload_file(): 28 | global cam_width 29 | global cam_height 30 | global html_opened 31 | 32 | file_to_upload = flask.request.files['media'].read() 33 | 34 | image = PIL.Image.frombytes(mode="RGBA", size=(cam_width, cam_height), data=file_to_upload) 35 | image = image.rotate(-90) 36 | image.save('out.png') 37 | 38 | print('File Uploaded Successfully.') 39 | 40 | f = open('out.png', 'rb') 41 | # im_base64 = base64.b64encode(image.tobytes()) 42 | im_base64 = base64.b64encode(f.read()) 43 | 44 | html_code = 'Displaying Uploaded Image

Uploaded Image to the Flask Server

Uploaded Image at the Flask Server' 45 | 46 | html_url = os.getcwd()+"/templates/test.html" 47 | f = open(html_url,'w') 48 | f.write(html_code) 49 | f.close() 50 | 51 | if html_opened == False: 52 | webbrowser.open(html_url) 53 | html_opened = True 54 | 55 | return "SUCCESS" 56 | 57 | app.run(host="192.168.16.103", port=6666, debug=True) 58 | -------------------------------------------------------------------------------- /Ch03/Kivy Client/main.py: -------------------------------------------------------------------------------- 1 | import kivy.app 2 | import requests 3 | import kivy.clock 4 | import kivy.uix.screenmanager 5 | import threading 6 | 7 | class Configure(kivy.uix.screenmanager.Screen): 8 | pass 9 | 10 | class Capture(kivy.uix.screenmanager.Screen): 11 | pass 12 | 13 | class PycamApp(kivy.app.App): 14 | num_images = 0 15 | 16 | def cam_size(self): 17 | camera = self.root.ids['camera'] 18 | cam_width_height = {'width': camera.resolution[0], 'height': camera.resolution[1]} 19 | 20 | ip_addr = self.root.ids['ip_address'].text 21 | port_number = self.root.ids['port_number'].text 22 | url = 'http://' + ip_addr + ':' + port_number + '/camSize' 23 | 24 | try: 25 | self.root.ids['cam_size'].text = "Trying to Establish a Connection..." 26 | requests.post(url, params=cam_width_height) 27 | self.root.ids['cam_size'].text = "Done." 28 | self.root.current = "capture" 29 | except requests.exceptions.ConnectionError: 30 | self.root.ids['cam_size'].text = "Connection Error! Make Sure Server is Active." 31 | 32 | def capture(self): 33 | kivy.clock.Clock.schedule_interval(self.upload_images, 0.5) 34 | 35 | def upload_images(self, *args): 36 | self.num_images = self.num_images + 1 37 | print("Uploading image", self.num_images) 38 | 39 | camera = self.root.ids['camera'] 40 | 41 | print("Image Size ", camera.resolution[0], camera.resolution[1]) 42 | print("Image corner ", camera.x, camera.y) 43 | 44 | pixels_data = camera.texture.get_region(x=camera.x, y=camera.y, width=camera.resolution[0], height=camera.resolution[1]).pixels 45 | 46 | ip_addr = self.root.ids['ip_address'].text 47 | port_number = self.root.ids['port_number'].text 48 | url = 'http://' + ip_addr + ':' + port_number + '/' 49 | files = {'media': pixels_data} 50 | 51 | t = threading.Thread(target=self.send_files_server, args=(files, url)) 52 | t.start() 53 | 54 | def build(self): 55 | pass 56 | 57 | def send_files_server(self, files, url): 58 | try: 59 | requests.post(url, files=files) 60 | except requests.exceptions.ConnectionError: 61 | self.root.ids['capture'].text = "Connection Error! Make Sure Server is Active." 62 | 63 | app = PycamApp() 64 | app.run() 65 | -------------------------------------------------------------------------------- /Ch03/Kivy Client/pycam.kv: -------------------------------------------------------------------------------- 1 | BoxLayout: 2 | orientation: "vertical" 3 | Camera: 4 | id: camera 5 | size_hint_y: 18 6 | resolution: (1280, 720) 7 | play: True 8 | canvas.before: 9 | PushMatrix: 10 | Rotate: 11 | angle: -90 12 | origin: root.width/2, root.height/2 13 | canvas.after: 14 | PopMatrix: 15 | TextInput: 16 | text: "192.168.43.231" 17 | id: ip_address 18 | size_hint_y: 1 19 | TextInput: 20 | text: "6666" 21 | id: port_number 22 | size_hint_y: 1 23 | Button: 24 | id: capture 25 | text: "Capture" 26 | size_hint_y: 1 27 | on_press: app.capture() 28 | Button: 29 | id: cam_size 30 | text: "Configure Server" 31 | size_hint_y: 1 32 | on_press: app.cam_size() -------------------------------------------------------------------------------- /Ch04/Flask Server/CamShareServer.py: -------------------------------------------------------------------------------- 1 | import flask 2 | import PIL.Image 3 | import base64 4 | import webbrowser 5 | import sys 6 | import os 7 | 8 | app = flask.Flask(import_name="FlaskUpload") 9 | 10 | cam_width = 0 11 | cam_height = 0 12 | 13 | html_opened = False 14 | 15 | @app.route('/camSize', methods = ['GET', 'POST']) 16 | def cam_size(): 17 | global cam_width 18 | global cam_height 19 | 20 | cam_width = int(float(flask.request.args["width"])) 21 | cam_height = int(float(flask.request.args["height"])) 22 | 23 | print('Width',cam_width,'& Height',cam_height,'Received Successfully.') 24 | 25 | return "OK" 26 | 27 | @app.route('/', methods = ['POST']) 28 | def upload_file(): 29 | global cam_width 30 | global cam_height 31 | global html_opened 32 | 33 | file_to_upload = flask.request.files['media'].read() 34 | 35 | image = PIL.Image.frombytes(mode="RGBA", size=(cam_width, cam_height), data=file_to_upload) 36 | image = image.rotate(-90) 37 | image.save('out.png') 38 | 39 | print('File Uploaded Successfully.') 40 | 41 | f = open('out.png', 'rb') 42 | # im_base64 = base64.b64encode(image.tobytes()) 43 | im_base64 = base64.b64encode(f.read()) 44 | 45 | html_code = 'Displaying Uploaded Image

Uploaded Image to the Flask Server

Uploaded Image at the Flask Server' 46 | 47 | # The HTML page is not required to be opened from the Python code but open it yourself externally. 48 | html_url = os.getcwd()+"/templates/test.html" 49 | f = open(html_url,'w') 50 | f.write(html_code) 51 | f.close() 52 | 53 | if html_opened == False: 54 | webbrowser.open(html_url) 55 | html_opened = True 56 | 57 | return "SUCCESS" 58 | 59 | ip_address = sys.argv[1]#"192.168.43.231" 60 | port_number = int(sys.argv[2])#6666 61 | app.run(host=ip_address, port=port_number, debug=True, threaded=True) 62 | 63 | -------------------------------------------------------------------------------- /Ch04/Kivy Client/buildozer.spec: -------------------------------------------------------------------------------- 1 | [app] 2 | 3 | # (str) Title of your application 4 | title = CamShare 5 | 6 | # (str) Package name 7 | package.name = myapp 8 | 9 | # (str) Package domain (needed for android/ios packaging) 10 | package.domain = camshare.camshare 11 | 12 | # (str) Source code where the main.py live 13 | source.dir = . 14 | 15 | # (list) Source files to include (let empty to include all the files) 16 | source.include_exts = py,png,jpg,kv,atlas 17 | 18 | # (list) List of inclusions using pattern matching 19 | #source.include_patterns = assets/*,images/*.png 20 | 21 | # (list) Source files to exclude (let empty to not exclude anything) 22 | #source.exclude_exts = spec 23 | 24 | # (list) List of directory to exclude (let empty to not exclude anything) 25 | source.exclude_dirs = temp, bin, CoinTex, CamShare 26 | 27 | # (list) List of exclusions using pattern matching 28 | #source.exclude_patterns = license,images/*/*.jpg 29 | 30 | # (str) Application versioning (method 1) 31 | version = 0.4 32 | 33 | # (str) Application versioning (method 2) 34 | # version.regex = __version__ = ['"](.*)['"] 35 | # version.filename = %(source.dir)s/main.py 36 | 37 | # (list) Application requirements 38 | # comma separated e.g. requirements = sqlite3,kivy 39 | requirements = requests,kivy 40 | #bootstrap = sdl2, pygame, opencv 41 | #requirements = plyer,kivy,opencv,numpy,pyjnius,ffmpeg, sqlite3, openssl 42 | #requirements.source.numpy = /home/ahmedgad/Desktop/numpy15 43 | 44 | # (str) Custom source folders for requirements 45 | # Sets custom source for any requirements with recipes 46 | # requirements.source.kivy = ../../kivy 47 | 48 | # (list) Garden requirements 49 | #garden_requirements = 50 | 51 | # (str) Presplash of the application 52 | presplash.filename = %(source.dir)s/presplash.png 53 | 54 | # (str) Icon of the application 55 | icon.filename = %(source.dir)s/icon.png 56 | 57 | # (str) Supported orientation (one of landscape, portrait or all) 58 | orientation = portrait 59 | 60 | # (list) List of service to declare 61 | #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY 62 | 63 | # 64 | # OSX Specific 65 | # 66 | 67 | # 68 | # author = © Copyright Info 69 | 70 | # change the major version of python used by the app 71 | osx.python_version = 3 72 | 73 | # Kivy version to use 74 | #osx.kivy_version = 1.9.1 75 | 76 | # 77 | # Android specific 78 | # 79 | 80 | # (bool) Indicate if the application should be fullscreen or not 81 | fullscreen = 1 82 | 83 | # (string) Presplash background color (for new android toolchain) 84 | # Supported formats are: #RRGGBB #AARRGGBB or one of the following names: 85 | # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, 86 | # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, 87 | # olive, purple, silver, teal. 88 | #android.presplash_color = #FFFFFF 89 | 90 | # (list) Permissions 91 | android.permissions = CAMERA, INTERNET 92 | 93 | # (int) Android API to use 94 | android.api = 27 95 | 96 | # (int) Minimum API required 97 | android.minapi = 18 98 | 99 | # (int) Android SDK version to use 100 | android.sdk = 27 101 | 102 | # (str) Android NDK version to use 103 | #android.ndk = 9c 104 | 105 | # (bool) Use --private data storage (True) or --dir public storage (False) 106 | #android.private_storage = True 107 | 108 | # (str) Android NDK directory (if empty, it will be automatically downloaded.) 109 | android.ndk_path = /home/ahmedgad/.buildozer/android/platform/android-ndk-r18b 110 | 111 | # (str) Android SDK directory (if empty, it will be automatically downloaded.) 112 | android.sdk_path = /home/ahmedgad/.buildozer/android/platform/android-sdk-linux 113 | 114 | # (str) ANT directory (if empty, it will be automatically downloaded.) 115 | #android.ant_path = /home/ahmedgad/.buildozer/android/platform/android-sdk-linux/apache-ant-1.9.4 116 | 117 | # (str) ANT directory (if empty, it will be automatically downloaded.) 118 | #android.ant_path = 119 | 120 | # (bool) If True, then skip trying to update the Android sdk 121 | # This can be useful to avoid excess Internet downloads or save time 122 | # when an update is due and you just want to test/build your package 123 | # android.skip_update = False 124 | 125 | # (str) Android entry point, default is ok for Kivy-based app 126 | #android.entrypoint = org.renpy.android.PythonActivity 127 | 128 | # (list) Pattern to whitelist for the whole project 129 | #android.whitelist = 130 | 131 | # (str) Path to a custom whitelist file 132 | #android.whitelist_src = 133 | 134 | # (str) Path to a custom blacklist file 135 | #android.blacklist_src = 136 | 137 | # (list) List of Java .jar files to add to the libs so that pyjnius can access 138 | # their classes. Don't add jars that you do not need, since extra jars can slow 139 | # down the build process. Allows wildcards matching, for example: 140 | # OUYA-ODK/libs/*.jar 141 | #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar 142 | 143 | # (list) List of Java files to add to the android project (can be java or a 144 | # directory containing the files) 145 | #android.add_src = 146 | 147 | # (list) Android AAR archives to add (currently works only with sdl2_gradle 148 | # bootstrap) 149 | #android.add_aars = 150 | 151 | # (list) Gradle dependencies to add (currently works only with sdl2_gradle 152 | # bootstrap) 153 | #android.gradle_dependencies = 154 | 155 | # (list) Java classes to add as activities to the manifest. 156 | #android.add_activites = com.example.ExampleActivity 157 | 158 | # (str) python-for-android branch to use, defaults to stable 159 | #p4a.branch = stable 160 | p4a.source_dir=/home/ahmedgad/Desktop/python-for-android 161 | 162 | #p4a.source_dir=/home/ahmedgad/Desktop/testp4a/python-for-android 163 | 164 | # (str) OUYA Console category. Should be one of GAME or APP 165 | # If you leave this blank, OUYA support will not be enabled 166 | #android.ouya.category = GAME 167 | 168 | # (str) Filename of OUYA Console icon. It must be a 732x412 png image. 169 | #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png 170 | 171 | # (str) XML file to include as an intent filters in tag 172 | #android.manifest.intent_filters = 173 | 174 | # (str) launchMode to set for the main activity 175 | #android.manifest.launch_mode = standard 176 | 177 | # (list) Android additional libraries to copy into libs/armeabi 178 | #android.add_libs_armeabi = libs/android/*.so 179 | #android.add_libs_armeabi_v7a = libs/android-v7/*.so 180 | #android.add_libs_x86 = libs/android-x86/*.so 181 | #android.add_libs_mips = libs/android-mips/*.so 182 | 183 | # (bool) Indicate whether the screen should stay on 184 | # Don't forget to add the WAKE_LOCK permission if you set this to True 185 | #android.wakelock = False 186 | 187 | # (list) Android application meta-data to set (key=value format) 188 | #android.meta_data = 189 | 190 | # (list) Android library project to add (will be added in the 191 | # project.properties automatically.) 192 | #android.library_references = 193 | 194 | # (str) Android logcat filters to use 195 | #android.logcat_filters = *:S python:D 196 | 197 | # (bool) Copy library instead of making a libpymodules.so 198 | #android.copy_libs = 1 199 | 200 | # (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86 201 | android.arch = armeabi-v7a 202 | 203 | # 204 | # Python for android (p4a) specific 205 | # 206 | 207 | # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) 208 | #p4a.source_dir = 209 | 210 | # (str) The directory in which python-for-android should look for your own build recipes (if any) 211 | #p4a.local_recipes = 212 | 213 | # (str) Filename to the hook for p4a 214 | #p4a.hook = 215 | 216 | # (str) Bootstrap to use for android builds 217 | # p4a.bootstrap = sdl2 218 | 219 | # (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) 220 | #p4a.port = 221 | 222 | 223 | # 224 | # iOS specific 225 | # 226 | 227 | # (str) Path to a custom kivy-ios folder 228 | #ios.kivy_ios_dir = ../kivy-ios 229 | 230 | # (str) Name of the certificate to use for signing the debug version 231 | # Get a list of available identities: buildozer ios list_identities 232 | #ios.codesign.debug = "iPhone Developer: ()" 233 | 234 | # (str) Name of the certificate to use for signing the release version 235 | #ios.codesign.release = %(ios.codesign.debug)s 236 | 237 | 238 | [buildozer] 239 | 240 | # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) 241 | log_level = 2 242 | 243 | # (int) Display warning if buildozer is run as root (0 = False, 1 = True) 244 | warn_on_root = 1 245 | 246 | # (str) Path to build artifact storage, absolute or relative to spec file 247 | # build_dir = ./.buildozer 248 | 249 | # (str) Path to build output (i.e. .apk, .ipa) storage 250 | # bin_dir = ./bin 251 | 252 | # ----------------------------------------------------------------------------- 253 | # List as sections 254 | # 255 | # You can define all the "list" as [section:key]. 256 | # Each line will be considered as a option to the list. 257 | # Let's take [app] / source.exclude_patterns. 258 | # Instead of doing: 259 | # 260 | #[app] 261 | #source.exclude_patterns = license,data/audio/*.wav,data/images/original/* 262 | # 263 | # This can be translated into: 264 | # 265 | #[app:source.exclude_patterns] 266 | #license 267 | #data/audio/*.wav 268 | #data/images/original/* 269 | # 270 | 271 | 272 | # ----------------------------------------------------------------------------- 273 | # Profiles 274 | # 275 | # You can extend section / key with a profile 276 | # For example, you want to deploy a demo version of your application without 277 | # HD content. You could first change the title to add "(demo)" in the name 278 | # and extend the excluded directories to remove the HD content. 279 | # 280 | #[app@demo] 281 | #title = My Application (demo) 282 | # 283 | #[app:source.exclude_patterns@demo] 284 | #images/hd/* 285 | # 286 | # Then, invoke the command line with the "demo" profile: 287 | # 288 | #buildozer --profile demo android debug 289 | -------------------------------------------------------------------------------- /Ch04/Kivy Client/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch04/Kivy Client/icon.png -------------------------------------------------------------------------------- /Ch04/Kivy Client/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch04/Kivy Client/logo.png -------------------------------------------------------------------------------- /Ch04/Kivy Client/main.py: -------------------------------------------------------------------------------- 1 | import kivy.app 2 | import requests 3 | import kivy.clock 4 | import kivy.uix.screenmanager 5 | import threading 6 | 7 | class Configure(kivy.uix.screenmanager.Screen): 8 | pass 9 | 10 | class Capture(kivy.uix.screenmanager.Screen): 11 | pass 12 | 13 | class PycamApp(kivy.app.App): 14 | num_images = 0 15 | 16 | def cam_size(self): 17 | camera = self.root.screens[1].ids['camera'] 18 | cam_width_height = {'width': camera.resolution[0], 'height': camera.resolution[1]} 19 | 20 | ip_addr = self.root.screens[0].ids['ip_address'].text 21 | port_number = self.root.screens[0].ids['port_number'].text 22 | url = 'http://'+ip_addr+':'+port_number+'/camSize' 23 | 24 | try: 25 | self.root.screens[0].ids['cam_size'].text = "Trying to Establish a Connection..." 26 | requests.post(url, params=cam_width_height) 27 | self.root.screens[0].ids['cam_size'].text = "Done." 28 | self.root.current = "capture" 29 | except requests.exceptions.ConnectionError: 30 | self.root.screens[0].ids['cam_size'].text = "Connection Error! Make Sure Server is Active." 31 | 32 | def capture(self): 33 | kivy.clock.Clock.schedule_interval(self.upload_images, 1.0) 34 | 35 | def upload_images(self, *args): 36 | self.num_images = self.num_images + 1 37 | print("Uploading image", self.num_images ) 38 | 39 | camera = self.root.screens[1].ids['camera'] 40 | 41 | print("Image Size ", camera.resolution[0], camera.resolution[1]) 42 | print("Image corner ", camera.x, camera.y) 43 | 44 | pixels_data = camera.texture.get_region(x=camera.x, y=camera.y, width=camera.resolution[0],height=camera.resolution[1]).pixels 45 | 46 | ip_addr = self.root.screens[0].ids['ip_address'].text 47 | port_number = self.root.screens[0].ids['port_number'].text 48 | url = 'http://'+ip_addr+':'+port_number+'/' 49 | files = {'media': pixels_data} 50 | 51 | t = threading.Thread(target=self.send_files_server, args=(files, url)) 52 | t.start() 53 | 54 | def build(self): 55 | pass 56 | 57 | def send_files_server(self, files, url): 58 | try: 59 | # self.root.screens[1].ids['capture'].text = "Trying to Establish a Connection..." 60 | requests.post(url, files=files) 61 | # self.root.screens[1].ids['capture'].text = "Capture Again!" 62 | except requests.exceptions.ConnectionError: 63 | self.root.screens[1].ids['capture'].text = "Connection Error! Make Sure Server is Active." 64 | 65 | if __name__ == "__main__": 66 | app = PycamApp() 67 | app.run() 68 | -------------------------------------------------------------------------------- /Ch04/Kivy Client/presplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch04/Kivy Client/presplash.png -------------------------------------------------------------------------------- /Ch04/Kivy Client/pycam.kv: -------------------------------------------------------------------------------- 1 | ScreenManager: 2 | Configure: 3 | Capture: 4 | 5 | : 6 | name: "capture" 7 | BoxLayout: 8 | orientation: "vertical" 9 | Camera: 10 | id: camera 11 | size_hint_y: 18 12 | resolution: (1024, 1024) 13 | allow_stretch: True 14 | play: True 15 | canvas.before: 16 | PushMatrix: 17 | Rotate: 18 | angle: -90 19 | origin: root.width/2, root.height/2 20 | canvas.after: 21 | PopMatrix: 22 | Button: 23 | id: capture 24 | font_size: 30 25 | text: "Capture" 26 | size_hint_y: 1 27 | on_press: app.capture() 28 | 29 | : 30 | name: "configure" 31 | BoxLayout: 32 | orientation: "vertical" 33 | Label: 34 | text: "1) Enter the IPv4 address of the server.\n2) Enter the port number. \n3) Press the Configure Server button. \nMake sure that the server is active." 35 | font_size: 20 36 | text_size: self.width, None 37 | size_hint_y: 1 38 | TextInput: 39 | text: "192.168.43.231" 40 | font_size: 30 41 | id: ip_address 42 | size_hint_y: 1 43 | TextInput: 44 | text: "6666" 45 | font_size: 30 46 | id: port_number 47 | size_hint_y: 1 48 | Button: 49 | id: cam_size 50 | font_size: 30 51 | text_size: self.width, None 52 | text: "Configure Server" 53 | size_hint_y: 1 54 | on_press: app.cam_size() 55 | 56 | -------------------------------------------------------------------------------- /Ch05-06/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/0.png -------------------------------------------------------------------------------- /Ch05-06/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/1.png -------------------------------------------------------------------------------- /Ch05-06/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/10.png -------------------------------------------------------------------------------- /Ch05-06/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/11.png -------------------------------------------------------------------------------- /Ch05-06/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/12.png -------------------------------------------------------------------------------- /Ch05-06/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/13.png -------------------------------------------------------------------------------- /Ch05-06/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/14.png -------------------------------------------------------------------------------- /Ch05-06/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/15.png -------------------------------------------------------------------------------- /Ch05-06/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/16.png -------------------------------------------------------------------------------- /Ch05-06/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/17.png -------------------------------------------------------------------------------- /Ch05-06/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/2.png -------------------------------------------------------------------------------- /Ch05-06/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/21.png -------------------------------------------------------------------------------- /Ch05-06/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/22.png -------------------------------------------------------------------------------- /Ch05-06/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/23.png -------------------------------------------------------------------------------- /Ch05-06/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/24.png -------------------------------------------------------------------------------- /Ch05-06/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/25.png -------------------------------------------------------------------------------- /Ch05-06/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/26.png -------------------------------------------------------------------------------- /Ch05-06/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/27.png -------------------------------------------------------------------------------- /Ch05-06/28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/28.png -------------------------------------------------------------------------------- /Ch05-06/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/29.png -------------------------------------------------------------------------------- /Ch05-06/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/3.png -------------------------------------------------------------------------------- /Ch05-06/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/4.png -------------------------------------------------------------------------------- /Ch05-06/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/5.png -------------------------------------------------------------------------------- /Ch05-06/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/6.png -------------------------------------------------------------------------------- /Ch05-06/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/7.png -------------------------------------------------------------------------------- /Ch05-06/91.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/91.png -------------------------------------------------------------------------------- /Ch05-06/92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/92.png -------------------------------------------------------------------------------- /Ch05-06/93.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/93.png -------------------------------------------------------------------------------- /Ch05-06/94.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/94.png -------------------------------------------------------------------------------- /Ch05-06/95.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/95.png -------------------------------------------------------------------------------- /Ch05-06/bg_cointex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/bg_cointex.png -------------------------------------------------------------------------------- /Ch05-06/buildozer.spec: -------------------------------------------------------------------------------- 1 | [app] 2 | 3 | # (str) Title of your application 4 | title = CoinTex 5 | 6 | # (str) Package name 7 | #package.name = reactfast 8 | 9 | # (str) Package domain (needed for android/ios packaging) 10 | #package.domain = cointex.cointex 11 | 12 | #package.name = reactfast 13 | #package.domain = cointex.cointex 14 | 15 | package.name = cointexreactfast 16 | package.domain = coin.tex 17 | 18 | # (str) Source code where the main.py live 19 | source.dir = . 20 | 21 | # (list) Source files to include (let empty to include all the files) 22 | source.include_exts = py,png,jpg,kv,atlas,wav 23 | 24 | # (list) List of inclusions using pattern matching 25 | #source.include_patterns = assets/*,images/*.png 26 | 27 | # (list) Source files to exclude (let empty to not exclude anything) 28 | #source.exclude_exts = spec 29 | 30 | # (list) List of directory to exclude (let empty to not exclude anything) 31 | source.exclude_dirs = bin 32 | 33 | # (list) List of exclusions using pattern matching 34 | #source.exclude_patterns = license,images/*/*.jpg 35 | 36 | # (str) Application versioning (method 1) 37 | version = 1.1 38 | 39 | # (str) Application versioning (method 2) 40 | # version.regex = __version__ = ['"](.*)['"] 41 | # version.filename = %(source.dir)s/main.py 42 | 43 | # (list) Application requirements 44 | # comma separated e.g. requirements = sqlite3,kivy 45 | requirements = kivy 46 | #requirements.source.numpy = /home/ahmedgad/Desktop/numpy15 47 | 48 | # (str) Custom source folders for requirements 49 | # Sets custom source for any requirements with recipes 50 | # requirements.source.kivy = ../../kivy 51 | 52 | # (list) Garden requirements 53 | #garden_requirements = 54 | 55 | # (str) Presplash of the application 56 | presplash.filename = %(source.dir)s/cointex_presplash.png 57 | 58 | # (str) Icon of the application 59 | icon.filename = %(source.dir)s/cointex_logo.png 60 | 61 | # (str) Supported orientation (one of landscape, portrait or all) 62 | orientation = landscape 63 | 64 | # (list) List of service to declare 65 | #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY 66 | 67 | # 68 | # OSX Specific 69 | # 70 | 71 | # 72 | # author = © Copyright Info 73 | 74 | # change the major version of python used by the app 75 | osx.python_version = 2 76 | 77 | # Kivy version to use 78 | #osx.kivy_version = 1.9.1 79 | 80 | # 81 | # Android specific 82 | # 83 | 84 | # (bool) Indicate if the application should be fullscreen or not 85 | fullscreen = 1 86 | 87 | # (string) Presplash background color (for new android toolchain) 88 | # Supported formats are: #RRGGBB #AARRGGBB or one of the following names: 89 | # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, 90 | # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, 91 | # olive, purple, silver, teal. 92 | #android.presplash_color = #FFFFFF 93 | 94 | # (list) Permissions 95 | #android.permissions = INTERNET 96 | 97 | # (int) Android API to use 98 | android.api = 19 99 | 100 | # (int) Minimum API required 101 | android.minapi = 19 102 | 103 | # (int) Android SDK version to use 104 | android.sdk = 27 105 | 106 | # (str) Android NDK version to use 107 | #android.ndk = 9c 108 | #android.ndk = 18b 109 | 110 | # (bool) Use --private data storage (True) or --dir public storage (False) 111 | #android.private_storage = True 112 | 113 | # (str) Android NDK directory (if empty, it will be automatically downloaded.) 114 | android.ndk_path = /home/ahmedgad/.buildozer/android/platform/android-ndk-r18b 115 | #android.ndk_path = /home/ahmedgad/.buildozer/android/platform/android-ndk-r9c 116 | #android.ndk_path = /home/ahmedgad/.buildozer/android/platform/android-ndk-r16b 117 | 118 | # (str) Android SDK directory (if empty, it will be automatically downloaded.) 119 | android.sdk_path = /home/ahmedgad/.buildozer/android/platform/android-sdk-linux 120 | 121 | # (str) Android NDK directory (if empty, it will be automatically downloaded.) 122 | #android.ndk_path = 123 | 124 | # (str) Android SDK directory (if empty, it will be automatically downloaded.) 125 | #android.sdk_path = 126 | 127 | # (str) ANT directory (if empty, it will be automatically downloaded.) 128 | #android.ant_path = /home/ahmedgad/.buildozer/android/platform/android-sdk-linux/apache-ant-1.9.4 129 | 130 | # (str) ANT directory (if empty, it will be automatically downloaded.) 131 | #android.ant_path = 132 | 133 | # (bool) If True, then skip trying to update the Android sdk 134 | # This can be useful to avoid excess Internet downloads or save time 135 | # when an update is due and you just want to test/build your package 136 | # android.skip_update = False 137 | 138 | # (str) Android entry point, default is ok for Kivy-based app 139 | #android.entrypoint = org.renpy.android.PythonActivity 140 | 141 | # (list) Pattern to whitelist for the whole project 142 | #android.whitelist = 143 | 144 | # (str) Path to a custom whitelist file 145 | #android.whitelist_src = 146 | 147 | # (str) Path to a custom blacklist file 148 | #android.blacklist_src = 149 | 150 | # (list) List of Java .jar files to add to the libs so that pyjnius can access 151 | # their classes. Don't add jars that you do not need, since extra jars can slow 152 | # down the build process. Allows wildcards matching, for example: 153 | # OUYA-ODK/libs/*.jar 154 | #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar 155 | 156 | # (list) List of Java files to add to the android project (can be java or a 157 | # directory containing the files) 158 | #android.add_src = 159 | 160 | # (list) Android AAR archives to add (currently works only with sdl2_gradle 161 | # bootstrap) 162 | #android.add_aars = 163 | 164 | # (list) Gradle dependencies to add (currently works only with sdl2_gradle 165 | # bootstrap) 166 | #android.gradle_dependencies = 167 | 168 | # (list) Java classes to add as activities to the manifest. 169 | #android.add_activites = com.example.ExampleActivity 170 | 171 | # (str) python-for-android branch to use, defaults to stable 172 | #p4a.branch = stable 173 | 174 | # (str) OUYA Console category. Should be one of GAME or APP 175 | # If you leave this blank, OUYA support will not be enabled 176 | #android.ouya.category = GAME 177 | 178 | # (str) Filename of OUYA Console icon. It must be a 732x412 png image. 179 | #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png 180 | 181 | # (str) XML file to include as an intent filters in tag 182 | #android.manifest.intent_filters = 183 | 184 | # (str) launchMode to set for the main activity 185 | #android.manifest.launch_mode = standard 186 | 187 | # (list) Android additional libraries to copy into libs/armeabi 188 | #android.add_libs_armeabi = libs/android/*.so 189 | #android.add_libs_armeabi_v7a = libs/android-v7/*.so 190 | #android.add_libs_x86 = libs/android-x86/*.so 191 | #android.add_libs_mips = libs/android-mips/*.so 192 | 193 | # (bool) Indicate whether the screen should stay on 194 | # Don't forget to add the WAKE_LOCK permission if you set this to True 195 | #android.wakelock = False 196 | 197 | # (list) Android application meta-data to set (key=value format) 198 | #android.meta_data = 199 | 200 | # (list) Android library project to add (will be added in the 201 | # project.properties automatically.) 202 | #android.library_references = 203 | 204 | # (str) Android logcat filters to use 205 | #android.logcat_filters = *:S python:D 206 | 207 | # (bool) Copy library instead of making a libpymodules.so 208 | #android.copy_libs = 1 209 | 210 | # (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86 211 | android.arch = armeabi-v7a 212 | 213 | # 214 | # Python for android (p4a) specific 215 | # 216 | 217 | # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) 218 | #p4a.source_dir = 219 | p4a.source_dir=/home/ahmedgad/Desktop/python-for-android 220 | #p4a.source_dir=/home/ahmedgad/Desktop/testp4a/python-for-android 221 | 222 | # (str) The directory in which python-for-android should look for your own build recipes (if any) 223 | #p4a.local_recipes = 224 | 225 | # (str) Filename to the hook for p4a 226 | #p4a.hook = 227 | 228 | # (str) Bootstrap to use for android builds 229 | # p4a.bootstrap = sdl2 230 | 231 | # (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) 232 | #p4a.port = 233 | 234 | 235 | # 236 | # iOS specific 237 | # 238 | 239 | # (str) Path to a custom kivy-ios folder 240 | #ios.kivy_ios_dir = ../kivy-ios 241 | 242 | # (str) Name of the certificate to use for signing the debug version 243 | # Get a list of available identities: buildozer ios list_identities 244 | #ios.codesign.debug = "iPhone Developer: ()" 245 | 246 | # (str) Name of the certificate to use for signing the release version 247 | #ios.codesign.release = %(ios.codesign.debug)s 248 | 249 | 250 | [buildozer] 251 | 252 | # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) 253 | log_level = 2 254 | 255 | # (int) Display warning if buildozer is run as root (0 = False, 1 = True) 256 | warn_on_root = 1 257 | 258 | # (str) Path to build artifact storage, absolute or relative to spec file 259 | # build_dir = ./.buildozer 260 | 261 | # (str) Path to build output (i.e. .apk, .ipa) storage 262 | # bin_dir = ./bin 263 | 264 | # ----------------------------------------------------------------------------- 265 | # List as sections 266 | # 267 | # You can define all the "list" as [section:key]. 268 | # Each line will be considered as a option to the list. 269 | # Let's take [app] / source.exclude_patterns. 270 | # Instead of doing: 271 | # 272 | #[app] 273 | #source.exclude_patterns = license,data/audio/*.wav,data/images/original/* 274 | # 275 | # This can be translated into: 276 | # 277 | #[app:source.exclude_patterns] 278 | #license 279 | #data/audio/*.wav 280 | #data/images/original/* 281 | # 282 | 283 | 284 | # ----------------------------------------------------------------------------- 285 | # Profiles 286 | # 287 | # You can extend section / key with a profile 288 | # For example, you want to deploy a demo version of your application without 289 | # HD content. You could first change the title to add "(demo)" in the name 290 | # and extend the excluded directories to remove the HD content. 291 | # 292 | #[app@demo] 293 | #title = My Application (demo) 294 | # 295 | #[app:source.exclude_patterns@demo] 296 | #images/hd/* 297 | # 298 | # Then, invoke the command line with the "demo" profile: 299 | # 300 | #buildozer --profile demo android debug 301 | -------------------------------------------------------------------------------- /Ch05-06/coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/coin.png -------------------------------------------------------------------------------- /Ch05-06/cointex_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/cointex_logo.png -------------------------------------------------------------------------------- /Ch05-06/cointex_presplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/cointex_presplash.png -------------------------------------------------------------------------------- /Ch05-06/fire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/fire.png -------------------------------------------------------------------------------- /Ch05-06/game_info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/game_info -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl1.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl10.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl11.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl12.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl13.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl14.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl15.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl16.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl17.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl18.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl19.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl2.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl20.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl3.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl3.png -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl4.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl4.png -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl5.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl5.png -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl6.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl6.png -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl7.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl8.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-bg/bg_lvl9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-bg/bg_lvl9.jpg -------------------------------------------------------------------------------- /Ch05-06/levels-images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/1.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/10.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/11.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/12.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/13.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/14.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/15.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/16.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/17.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/18.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/19.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/2.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/20.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/21.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/22.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/23.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/24.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/3.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/4.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/5.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/6.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/7.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/8.png -------------------------------------------------------------------------------- /Ch05-06/levels-images/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/levels-images/9.png -------------------------------------------------------------------------------- /Ch05-06/main.py: -------------------------------------------------------------------------------- 1 | import kivy.app 2 | import kivy.uix.screenmanager 3 | import kivy.uix.image 4 | import random 5 | import kivy.core.audio 6 | import os 7 | import functools 8 | import kivy.uix.behaviors 9 | import pickle 10 | 11 | class TestApp(kivy.app.App): 12 | 13 | def on_start(self): 14 | music_dir = os.getcwd()+"/music/" 15 | self.main_bg_music = kivy.core.audio.SoundLoader.load(music_dir+"bg_music_piano_flute.wav") 16 | self.main_bg_music.loop = True 17 | self.main_bg_music.play() 18 | 19 | next_level_num, congrats_displayed_once = self.read_game_info() 20 | self.activate_levels(next_level_num, congrats_displayed_once) 21 | 22 | def read_game_info(self): 23 | try: 24 | game_info_file = open("game_info",'rb') 25 | game_info = pickle.load(game_info_file) 26 | return game_info[0]['lastlvl'], game_info[0]['congrats_displayed_once'] 27 | game_info_file.close() 28 | except: 29 | print("CoinTex FileNotFoundError: Game info file is not found. Game starts from level 1.") 30 | return 1, False 31 | 32 | def activate_levels(self, next_level_num, congrats_displayed_once): 33 | num_levels = len(self.root.screens[0].ids['lvls_imagebuttons'].children) 34 | 35 | levels_imagebuttons = self.root.screens[0].ids['lvls_imagebuttons'].children 36 | for i in range(num_levels-next_level_num, num_levels): 37 | levels_imagebuttons[i].disabled = False 38 | levels_imagebuttons[i].color = [1,1,1,1] 39 | 40 | for i in range(0, num_levels-next_level_num): 41 | levels_imagebuttons[i].disabled = True 42 | levels_imagebuttons[i].color = [1,1,1,0.5] 43 | 44 | if next_level_num == (num_levels+1) and congrats_displayed_once == False: 45 | self.root.current = "alllevelscompleted" 46 | 47 | def screen_on_pre_leave(self, screen_num): 48 | curr_screen = self.root.screens[screen_num] 49 | for i in range(curr_screen.num_monsters): curr_screen.ids['monster'+str(i+1)+'_image_lvl'+str(screen_num)].pos_hint = {'x': 0.8, 'y': 0.8} 50 | curr_screen.ids['character_image_lvl'+str(screen_num)].pos_hint = {'x': 0.0, 'y': 0.0} 51 | 52 | next_level_num, congrats_displayed_once = self.read_game_info() 53 | self.activate_levels(next_level_num, congrats_displayed_once) 54 | 55 | def screen_on_pre_enter(self, screen_num): 56 | curr_screen = self.root.screens[screen_num] 57 | curr_screen.character_killed = False 58 | curr_screen.num_coins_collected = 0 59 | curr_screen.ids['character_image_lvl'+str(screen_num)].im_num = curr_screen.ids['character_image_lvl'+str(screen_num)].start_im_num 60 | for i in range(curr_screen.num_monsters): curr_screen.ids['monster'+str(i+1)+'_image_lvl'+str(screen_num)].im_num = curr_screen.ids['monster'+str(i+1)+'_image_lvl'+str(screen_num)].start_im_num 61 | curr_screen.ids['num_coins_collected_lvl'+str(screen_num)].text = "Coins 0/"+str(curr_screen.num_coins) 62 | curr_screen.ids['level_number_lvl'+str(screen_num)].text = "Level "+str(screen_num) 63 | 64 | curr_screen.num_collisions_hit = 0 65 | remaining_life_percent_lvl_widget = curr_screen.ids['remaining_life_percent_lvl'+str(screen_num)] 66 | remaining_life_percent_lvl_widget.size_hint = (remaining_life_percent_lvl_widget.remaining_life_size_hint_x, remaining_life_percent_lvl_widget.size_hint[1]) 67 | 68 | for i in range(curr_screen.num_fires): curr_screen.ids['fire'+str(i+1)+'_lvl'+str(screen_num)].pos_hint = {'x': 1.1, 'y': 1.1} 69 | 70 | for key, coin in curr_screen.coins_ids.items(): 71 | curr_screen.ids['layout_lvl'+str(screen_num)].remove_widget(coin) 72 | curr_screen.coins_ids = {} 73 | 74 | coin_width = 0.05 75 | coin_height = 0.05 76 | 77 | curr_screen = self.root.screens[screen_num] 78 | 79 | section_width = 1.0/curr_screen.num_coins 80 | for k in range(curr_screen.num_coins): 81 | x = random.uniform(section_width*k, section_width*(k+1)-coin_width) 82 | y = random.uniform(0, 1-coin_height) 83 | coin = kivy.uix.image.Image(source="coin.png", size_hint=(coin_width, coin_height), pos_hint={'x': x, 'y': y}, allow_stretch=True) 84 | curr_screen.ids['layout_lvl'+str(screen_num)].add_widget(coin, index=-1) 85 | curr_screen.coins_ids['coin'+str(k)] = coin 86 | 87 | def screen_on_enter(self, screen_num): 88 | music_dir = os.getcwd()+"/music/" 89 | self.bg_music = kivy.core.audio.SoundLoader.load(music_dir+"bg_music_piano.wav") 90 | self.bg_music.loop = True 91 | 92 | self.coin_sound = kivy.core.audio.SoundLoader.load(music_dir+"coin.wav") 93 | self.level_completed_sound = kivy.core.audio.SoundLoader.load(music_dir+"level_completed_flaute.wav") 94 | self.char_death_sound = kivy.core.audio.SoundLoader.load(music_dir+"char_death_flaute.wav") 95 | 96 | self.bg_music.play() 97 | 98 | curr_screen = self.root.screens[screen_num] 99 | for i in range(curr_screen.num_monsters): 100 | monster_image = curr_screen.ids['monster'+str(i+1)+'_image_lvl'+str(screen_num)] 101 | new_pos = (random.uniform(0.0, 1 - monster_image.size_hint[0]/4), random.uniform(0.0, 1 - monster_image.size_hint[1]/4)) 102 | self.start_monst_animation(monster_image=monster_image, new_pos=new_pos, anim_duration=random.uniform(monster_image.monst_anim_duration_low, monster_image.monst_anim_duration_high)) 103 | 104 | for i in range(curr_screen.num_fires): 105 | fire_widget = curr_screen.ids['fire'+str(i+1)+'_lvl'+str(screen_num)] 106 | self.start_fire_animation(fire_widget=fire_widget, pos=(0.0, 0.5), anim_duration=5.0) 107 | 108 | def start_monst_animation(self, monster_image, new_pos, anim_duration): 109 | monst_anim = kivy.animation.Animation(pos_hint={'x': new_pos[0], 'y': new_pos[1]}, im_num=monster_image.end_im_num,duration=anim_duration) 110 | monst_anim.bind(on_complete=self.monst_animation_completed) 111 | monst_anim.start(monster_image) 112 | 113 | def monst_animation_completed(self, *args): 114 | monster_image = args[1] 115 | monster_image.im_num = monster_image.start_im_num 116 | 117 | new_pos = (random.uniform(0.0, 1 - monster_image.size_hint[0]/4), random.uniform(0.0, 1 - monster_image.size_hint[1]/4)) 118 | self.start_monst_animation(monster_image=monster_image, new_pos= new_pos,anim_duration=random.uniform(monster_image.monst_anim_duration_low, monster_image.monst_anim_duration_high)) 119 | 120 | def monst_pos_hint(self, monster_image): 121 | screen_num = int(monster_image.parent.parent.name[5:]) 122 | curr_screen = self.root.screens[screen_num] 123 | character_image = curr_screen.ids['character_image_lvl'+str(screen_num)] 124 | 125 | character_center = character_image.center 126 | monster_center = monster_image.center 127 | 128 | gab_x = character_image.width / 2 129 | gab_y = character_image.height / 2 130 | if character_image.collide_widget(monster_image) and abs(character_center[0] - monster_center[0]) <= gab_x and abs(character_center[1] - monster_center[1]) <= gab_y: 131 | curr_screen.num_collisions_hit = curr_screen.num_collisions_hit + 1 132 | life_percent = float(curr_screen.num_collisions_hit)/float(curr_screen.num_collisions_level) 133 | 134 | # life_remaining_percent = 100-round(life_percent, 2)*100 135 | # remaining_life_percent_lvl_widget.text = str(int(life_remaining_percent))+"%" 136 | remaining_life_percent_lvl_widget=curr_screen.ids['remaining_life_percent_lvl'+str(screen_num)] 137 | remaining_life_size_hint_x = remaining_life_percent_lvl_widget.remaining_life_size_hint_x 138 | remaining_life_percent_lvl_widget.size_hint = (remaining_life_size_hint_x-remaining_life_size_hint_x*life_percent, remaining_life_percent_lvl_widget.size_hint[1]) 139 | 140 | if curr_screen.num_collisions_hit == curr_screen.num_collisions_level: 141 | self.bg_music.stop() 142 | self.char_death_sound.play() 143 | curr_screen.character_killed = True 144 | 145 | kivy.animation.Animation.cancel_all(character_image) 146 | for i in range(curr_screen.num_monsters): kivy.animation.Animation.cancel_all(curr_screen.ids['monster'+str(i+1)+'_image_lvl'+str(screen_num)]) 147 | for i in range(curr_screen.num_fires): kivy.animation.Animation.cancel_all(curr_screen.ids['fire'+str(i+1)+'_lvl'+str(screen_num)]) 148 | 149 | character_image.im_num = character_image.dead_start_im_num 150 | char_anim = kivy.animation.Animation(im_num=character_image.dead_end_im_num, duration=1.0) 151 | char_anim.start(character_image) 152 | kivy.clock.Clock.schedule_once(functools.partial(self.back_to_main_screen, curr_screen.parent), 3) 153 | 154 | def change_monst_im(self, monster_image): 155 | monster_image.source = str(int(monster_image.im_num)) + ".png" 156 | 157 | def touch_down_handler(self, screen_num, args): 158 | curr_screen = self.root.screens[screen_num] 159 | if curr_screen.character_killed == False: 160 | self.start_char_animation(screen_num, args[1].spos) 161 | 162 | def start_char_animation(self, screen_num, touch_pos): 163 | curr_screen = self.root.screens[screen_num] 164 | character_image = curr_screen.ids['character_image_lvl'+str(screen_num)] 165 | character_image.im_num = character_image.start_im_num 166 | char_anim = kivy.animation.Animation(pos_hint={'x': touch_pos[0] - character_image.size_hint[0] / 2,'y': touch_pos[1] - character_image.size_hint[1] / 2}, im_num=character_image.end_im_num, duration=curr_screen.char_anim_duration) 167 | char_anim.bind(on_complete=self.char_animation_completed) 168 | char_anim.start(character_image) 169 | 170 | def char_animation_completed(self, *args): 171 | character_image = args[1] 172 | character_image.im_num = character_image.start_im_num 173 | 174 | def char_pos_hint(self, character_image): 175 | screen_num = int(character_image.parent.parent.name[5:]) 176 | character_center = character_image.center 177 | 178 | gab_x = character_image.width / 3 179 | gab_y = character_image.height / 3 180 | coins_to_delete = [] 181 | curr_screen = self.root.screens[screen_num] 182 | 183 | for coin_key, curr_coin in curr_screen.coins_ids.items(): 184 | curr_coin_center = curr_coin.center 185 | if character_image.collide_widget(curr_coin) and abs(character_center[0] - curr_coin_center[0]) <= gab_x and abs(character_center[1] - curr_coin_center[1]) <= gab_y: 186 | self.coin_sound.play() 187 | coins_to_delete.append(coin_key) 188 | curr_screen.ids['layout_lvl'+str(screen_num)].remove_widget(curr_coin) 189 | curr_screen.num_coins_collected = curr_screen.num_coins_collected + 1 190 | curr_screen.ids['num_coins_collected_lvl'+str(screen_num)].text = "Coins "+str(curr_screen.num_coins_collected)+"/"+str(curr_screen.num_coins) 191 | if curr_screen.num_coins_collected == curr_screen.num_coins: 192 | self.bg_music.stop() 193 | self.level_completed_sound.play() 194 | kivy.clock.Clock.schedule_once(functools.partial(self.back_to_main_screen, curr_screen.parent), 3) 195 | for i in range(curr_screen.num_monsters): kivy.animation.Animation.cancel_all(curr_screen.ids['monster'+str(i+1)+'_image_lvl'+str(screen_num)]) 196 | for i in range(curr_screen.num_fires): kivy.animation.Animation.cancel_all(curr_screen.ids['fire'+str(i+1)+'_lvl'+str(screen_num)]) 197 | 198 | next_level_num, congrats_displayed_once = self.read_game_info() 199 | if (screen_num+1) > next_level_num: 200 | game_info_file = open("game_info",'wb') 201 | pickle.dump([{'lastlvl':screen_num+1, "congrats_displayed_once": False}], game_info_file) 202 | game_info_file.close() 203 | else: 204 | game_info_file = open("game_info",'wb') 205 | pickle.dump([{'lastlvl':next_level_num, "congrats_displayed_once": True}], game_info_file) 206 | game_info_file.close() 207 | 208 | if len(coins_to_delete) > 0: 209 | for coin_key in coins_to_delete: 210 | del curr_screen.coins_ids[coin_key] 211 | 212 | def change_char_im(self, character_image): 213 | character_image.source = str(int(character_image.im_num)) + ".png" 214 | 215 | def start_fire_animation(self, fire_widget, pos, anim_duration): 216 | fire_anim = kivy.animation.Animation(pos_hint=fire_widget.fire_start_pos_hint, duration=fire_widget.fire_anim_duration)+kivy.animation.Animation(pos_hint=fire_widget.fire_end_pos_hint, duration=fire_widget.fire_anim_duration) 217 | fire_anim.repeat = True 218 | fire_anim.start(fire_widget) 219 | 220 | def fire_pos_hint(self, fire_widget): 221 | screen_num = int(fire_widget.parent.parent.name[5:]) 222 | curr_screen = self.root.screens[screen_num] 223 | character_image = curr_screen.ids['character_image_lvl'+str(screen_num)] 224 | 225 | character_center = character_image.center 226 | fire_center = fire_widget.center 227 | 228 | gab_x = character_image.width / 3 229 | gab_y = character_image.height / 3 230 | if character_image.collide_widget(fire_widget) and abs(character_center[0] - fire_center[0]) <= gab_x and abs(character_center[1] - fire_center[1]) <= gab_y: 231 | curr_screen.num_collisions_hit = curr_screen.num_collisions_hit + 1 232 | life_percent = float(curr_screen.num_collisions_hit)/float(curr_screen.num_collisions_level) 233 | 234 | remaining_life_percent_lvl_widget = curr_screen.ids['remaining_life_percent_lvl'+str(screen_num)] 235 | # life_remaining_percent = 100-round(life_percent, 2)*100 236 | # remaining_life_percent_lvl_widget.text = str(int(life_remaining_percent))+"%" 237 | 238 | remaining_life_size_hint_x = remaining_life_percent_lvl_widget.remaining_life_size_hint_x 239 | remaining_life_percent_lvl_widget.size_hint = (remaining_life_size_hint_x-remaining_life_size_hint_x*life_percent, remaining_life_percent_lvl_widget.size_hint[1]) 240 | 241 | if curr_screen.num_collisions_hit == curr_screen.num_collisions_level: 242 | self.bg_music.stop() 243 | self.char_death_sound.play() 244 | curr_screen.character_killed = True 245 | 246 | kivy.animation.Animation.cancel_all(character_image) 247 | for i in range(curr_screen.num_monsters): kivy.animation.Animation.cancel_all(curr_screen.ids['monster'+str(i+1)+'_image_lvl'+str(screen_num)]) 248 | for i in range(curr_screen.num_fires): kivy.animation.Animation.cancel_all(curr_screen.ids['fire'+str(i+1)+'_lvl'+str(screen_num)]) 249 | 250 | character_image.im_num = character_image.dead_start_im_num 251 | char_anim = kivy.animation.Animation(im_num=character_image.dead_end_im_num, duration=1.0) 252 | char_anim.start(character_image) 253 | kivy.clock.Clock.schedule_once(functools.partial(self.back_to_main_screen, curr_screen.parent), 3) 254 | 255 | def back_to_main_screen(self, screenManager, *args): 256 | screenManager.current = "main" 257 | 258 | def main_screen_on_enter(self): 259 | self.main_bg_music.play() 260 | 261 | def main_screen_on_leave(self): 262 | self.main_bg_music.stop() 263 | 264 | class ImageButton(kivy.uix.behaviors.ButtonBehavior, kivy.uix.image.Image): 265 | pass 266 | 267 | class MainScreen(kivy.uix.screenmanager.Screen): 268 | pass 269 | 270 | class AboutUs(kivy.uix.screenmanager.Screen): 271 | pass 272 | 273 | class AllLevelsCompleted(kivy.uix.screenmanager.Screen): 274 | pass 275 | 276 | class Level1(kivy.uix.screenmanager.Screen): 277 | character_killed = False 278 | num_coins = 5 279 | num_coins_collected = 0 280 | coins_ids = {} 281 | char_anim_duration = 1.0 282 | num_monsters = 1 283 | num_fires = 0 284 | num_collisions_hit = 0 285 | num_collisions_level = 20 286 | 287 | class Level2(kivy.uix.screenmanager.Screen): 288 | character_killed = False 289 | num_coins = 8 290 | num_coins_collected = 0 291 | coins_ids = {} 292 | char_anim_duration = 1.1 293 | num_monsters = 1 294 | num_fires = 0 295 | num_collisions_hit = 0 296 | num_collisions_level = 30 297 | 298 | class Level3(kivy.uix.screenmanager.Screen): 299 | character_killed = False 300 | num_coins = 12 301 | num_coins_collected = 0 302 | coins_ids = {} 303 | char_anim_duration = 1.2 304 | num_monsters = 1 305 | num_fires = 0 306 | num_collisions_hit = 0 307 | num_collisions_level = 30 308 | 309 | class Level4(kivy.uix.screenmanager.Screen): 310 | character_killed = False 311 | num_coins = 10 312 | num_coins_collected = 0 313 | coins_ids = {} 314 | char_anim_duration = 1.2 315 | num_monsters = 1 316 | num_fires = 1 317 | num_collisions_hit = 0 318 | num_collisions_level = 20 319 | 320 | class Level5(kivy.uix.screenmanager.Screen): 321 | character_killed = False 322 | num_coins = 15 323 | num_coins_collected = 0 324 | coins_ids = {} 325 | char_anim_duration = 1.3 326 | num_monsters = 1 327 | num_fires = 2 328 | num_collisions_hit = 0 329 | num_collisions_level = 20 330 | 331 | class Level6(kivy.uix.screenmanager.Screen): 332 | character_killed = False 333 | num_coins = 12 334 | num_coins_collected = 0 335 | coins_ids = {} 336 | char_anim_duration = 1.3 337 | num_monsters = 1 338 | num_fires = 3 339 | num_collisions_hit = 0 340 | num_collisions_level = 20 341 | 342 | class Level7(kivy.uix.screenmanager.Screen): 343 | character_killed = False 344 | num_coins = 10 345 | num_coins_collected = 0 346 | coins_ids = {} 347 | char_anim_duration = 1.4 348 | num_monsters = 3 349 | num_fires = 0 350 | num_collisions_hit = 0 351 | num_collisions_level = 25 352 | 353 | class Level8(kivy.uix.screenmanager.Screen): 354 | character_killed = False 355 | num_coins = 15 356 | num_coins_collected = 0 357 | coins_ids = {} 358 | char_anim_duration = 1.4 359 | num_monsters = 2 360 | num_fires = 0 361 | num_collisions_hit = 0 362 | num_collisions_level = 25 363 | 364 | class Level9(kivy.uix.screenmanager.Screen): 365 | character_killed = False 366 | num_coins = 12 367 | num_coins_collected = 0 368 | coins_ids = {} 369 | char_anim_duration = 1.5 370 | num_monsters = 2 371 | num_fires = 0 372 | num_collisions_hit = 0 373 | num_collisions_level = 25 374 | 375 | class Level10(kivy.uix.screenmanager.Screen): 376 | character_killed = False 377 | num_coins = 14 378 | num_coins_collected = 0 379 | coins_ids = {} 380 | char_anim_duration = 1.5 381 | num_monsters = 3 382 | num_fires = 0 383 | num_collisions_hit = 0 384 | num_collisions_level = 30 385 | 386 | class Level11(kivy.uix.screenmanager.Screen): 387 | character_killed = False 388 | num_coins = 15 389 | num_coins_collected = 0 390 | coins_ids = {} 391 | char_anim_duration = 1.6 392 | num_monsters = 2 393 | num_fires = 1 394 | num_collisions_hit = 0 395 | num_collisions_level = 30 396 | 397 | class Level12(kivy.uix.screenmanager.Screen): 398 | character_killed = False 399 | num_coins = 12 400 | num_coins_collected = 0 401 | coins_ids = {} 402 | char_anim_duration = 1.6 403 | num_monsters = 2 404 | num_fires = 1 405 | num_collisions_hit = 0 406 | num_collisions_level = 30 407 | 408 | class Level13(kivy.uix.screenmanager.Screen): 409 | character_killed = False 410 | num_coins = 10 411 | num_coins_collected = 0 412 | coins_ids = {} 413 | char_anim_duration = 1.7 414 | num_monsters = 2 415 | num_fires = 2 416 | num_collisions_hit = 0 417 | num_collisions_level = 20 418 | 419 | class Level14(kivy.uix.screenmanager.Screen): 420 | character_killed = False 421 | num_coins = 15 422 | num_coins_collected = 0 423 | coins_ids = {} 424 | char_anim_duration = 1.7 425 | num_monsters = 0 426 | num_fires = 6 427 | num_collisions_hit = 0 428 | num_collisions_level = 30 429 | 430 | class Level15(kivy.uix.screenmanager.Screen): 431 | character_killed = False 432 | num_coins = 16 433 | num_coins_collected = 0 434 | coins_ids = {} 435 | char_anim_duration = 1.8 436 | num_monsters = 2 437 | num_fires = 3 438 | num_collisions_hit = 0 439 | num_collisions_level = 30 440 | 441 | class Level16(kivy.uix.screenmanager.Screen): 442 | character_killed = False 443 | num_coins = 15 444 | num_coins_collected = 0 445 | coins_ids = {} 446 | char_anim_duration = 1.8 447 | num_monsters = 3 448 | num_fires = 2 449 | num_collisions_hit = 0 450 | num_collisions_level = 35 451 | 452 | class Level17(kivy.uix.screenmanager.Screen): 453 | character_killed = False 454 | num_coins = 10 455 | num_coins_collected = 0 456 | coins_ids = {} 457 | char_anim_duration = 1.3 458 | num_monsters = 0 459 | num_fires = 4 460 | num_collisions_hit = 0 461 | num_collisions_level = 30 462 | 463 | class Level18(kivy.uix.screenmanager.Screen): 464 | character_killed = False 465 | num_coins = 15 466 | num_coins_collected = 0 467 | coins_ids = {} 468 | char_anim_duration = 1.5 469 | num_monsters = 3 470 | num_fires = 4 471 | num_collisions_hit = 0 472 | num_collisions_level = 30 473 | 474 | class Level19(kivy.uix.screenmanager.Screen): 475 | character_killed = False 476 | num_coins = 12 477 | num_coins_collected = 0 478 | coins_ids = {} 479 | char_anim_duration = 1.2 480 | num_monsters = 0 481 | num_fires = 6 482 | num_collisions_hit = 0 483 | num_collisions_level = 30 484 | 485 | class Level20(kivy.uix.screenmanager.Screen): 486 | character_killed = False 487 | num_coins = 15 488 | num_coins_collected = 0 489 | coins_ids = {} 490 | char_anim_duration = 1.1 491 | num_monsters = 0 492 | num_fires = 8 493 | num_collisions_hit = 0 494 | num_collisions_level = 30 495 | 496 | class Level20(kivy.uix.screenmanager.Screen): 497 | character_killed = False 498 | num_coins = 20 499 | num_coins_collected = 0 500 | coins_ids = {} 501 | char_anim_duration = 1.1 502 | num_monsters = 2 503 | num_fires = 4 504 | num_collisions_hit = 0 505 | num_collisions_level = 30 506 | 507 | class Level21(kivy.uix.screenmanager.Screen): 508 | character_killed = False 509 | num_coins = 18 510 | num_coins_collected = 0 511 | coins_ids = {} 512 | char_anim_duration = 1.3 513 | num_monsters = 2 514 | num_fires = 4 515 | num_collisions_hit = 0 516 | num_collisions_level = 30 517 | 518 | class Level22(kivy.uix.screenmanager.Screen): 519 | character_killed = False 520 | num_coins = 20 521 | num_coins_collected = 0 522 | coins_ids = {} 523 | char_anim_duration = 1.3 524 | num_monsters = 2 525 | num_fires = 4 526 | num_collisions_hit = 0 527 | num_collisions_level = 30 528 | 529 | class Level23(kivy.uix.screenmanager.Screen): 530 | character_killed = False 531 | num_coins = 25 532 | num_coins_collected = 0 533 | coins_ids = {} 534 | char_anim_duration = 1.1 535 | num_monsters = 2 536 | num_fires = 2 537 | num_collisions_hit = 0 538 | num_collisions_level = 30 539 | 540 | class Level24(kivy.uix.screenmanager.Screen): 541 | character_killed = False 542 | num_coins = 20 543 | num_coins_collected = 0 544 | coins_ids = {} 545 | char_anim_duration = 1.1 546 | num_monsters = 3 547 | num_fires = 2 548 | num_collisions_hit = 0 549 | num_collisions_level = 30 550 | 551 | app = TestApp(title="CoinTex") 552 | app.run() 553 | 554 | -------------------------------------------------------------------------------- /Ch05-06/music/bg_music_piano.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/music/bg_music_piano.wav -------------------------------------------------------------------------------- /Ch05-06/music/bg_music_piano_flute.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/music/bg_music_piano_flute.wav -------------------------------------------------------------------------------- /Ch05-06/music/char_death_flaute.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/music/char_death_flaute.wav -------------------------------------------------------------------------------- /Ch05-06/music/coin.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/music/coin.wav -------------------------------------------------------------------------------- /Ch05-06/music/level_completed_flaute.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/music/level_completed_flaute.wav -------------------------------------------------------------------------------- /Ch05-06/other-images/About-Us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/other-images/About-Us.png -------------------------------------------------------------------------------- /Ch05-06/other-images/Congratulations-Passed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/other-images/Congratulations-Passed.png -------------------------------------------------------------------------------- /Ch05-06/other-images/Main-Screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch05-06/other-images/Main-Screen.png -------------------------------------------------------------------------------- /Ch05-06/test.kv: -------------------------------------------------------------------------------- 1 | ScreenManager: 2 | MainScreen: 3 | Level1: 4 | Level2: 5 | Level3: 6 | Level4: 7 | Level5: 8 | Level6: 9 | Level7: 10 | Level8: 11 | Level9: 12 | Level10: 13 | Level11: 14 | Level12: 15 | Level13: 16 | Level14: 17 | Level15: 18 | Level16: 19 | Level17: 20 | Level18: 21 | Level19: 22 | Level20: 23 | Level21: 24 | Level22: 25 | Level23: 26 | Level24: 27 | AboutUs: 28 | AllLevelsCompleted: 29 | 30 | : 31 | name: "aboutus" 32 | GridLayout: 33 | rows: 2 34 | canvas.before: 35 | Color: 36 | rgba: (0.6, 0.6, 0.6, 0.8) 37 | Rectangle: 38 | pos: self.pos 39 | size: self.size 40 | source: "bg_cointex.png" 41 | Label: 42 | size_hint_y: 0.9 43 | text_size: self.size 44 | font_size: 20 45 | halign: 'left' 46 | valign: 'top' 47 | text: "CoinTex version 1.2 is developed by Ahmed Fawzy Gad who is interested in machine learning, deep learning, computer vision, and Python. The game is completely developed in Python using the Kivy cross-platform framework.\n\nFeel free to contact me for any questions or recommendations:\nE-mail: ahmed.f.gad@gmail.com\nFacebook: https://www.facebook.com/ahmed.f.gadd\nLinkedIn: https://www.linkedin.com/in/ahmedfgad\nTowardsDataScience: https://towardsdatascience.com/@ahmedfgad \nResearchGate: https://www.researchgate.net/profile/Ahmed_Gad13" 48 | ImageButton: 49 | size_hint_y: 0.1 50 | source: "other-images/Main-Screen.png" 51 | on_release: app.root.current="main" 52 | 53 | : 54 | name: "alllevelscompleted" 55 | GridLayout: 56 | rows: 2 57 | canvas.before: 58 | Color: 59 | rgba: (0.6, 0.6, 0.6, 0.8) 60 | Rectangle: 61 | pos: self.pos 62 | size: self.size 63 | source: "bg_cointex.png" 64 | Image: 65 | size_hint_y: 0.9 66 | source: "other-images/Congratulations-Passed.png" 67 | ImageButton: 68 | size_hint_y: 0.1 69 | source: "other-images/Main-Screen.png" 70 | on_release: app.root.current="main" 71 | 72 | : 73 | name: "main" 74 | on_enter: app.main_screen_on_enter() 75 | on_leave: app.main_screen_on_leave() 76 | BoxLayout: 77 | orientation: "vertical" 78 | BoxLayout: 79 | size_hint_y: 0.08 80 | ImageButton: 81 | source: "./other-images/About-Us.png" 82 | on_release: app.root.current="aboutus" 83 | GridLayout: 84 | id: lvls_imagebuttons 85 | cols: 4 86 | spacing: (5,5) 87 | size_hint_y: 0.92 88 | canvas.before: 89 | Rectangle: 90 | pos: self.pos 91 | size: self.size 92 | source: "bg_cointex.png" 93 | ImageButton: 94 | source: "levels-images/1.png" 95 | on_release: app.root.current="level1" 96 | ImageButton: 97 | source: "levels-images/2.png" 98 | on_release: app.root.current="level2" 99 | ImageButton: 100 | source: "levels-images/3.png" 101 | on_release: app.root.current="level3" 102 | ImageButton: 103 | source: "levels-images/4.png" 104 | on_release: app.root.current="level4" 105 | ImageButton: 106 | source: "levels-images/5.png" 107 | on_release: app.root.current="level5" 108 | ImageButton: 109 | source: "levels-images/6.png" 110 | on_release: app.root.current="level6" 111 | ImageButton: 112 | source: "levels-images/7.png" 113 | on_release: app.root.current="level7" 114 | ImageButton: 115 | source: "levels-images/8.png" 116 | on_release: app.root.current="level8" 117 | ImageButton: 118 | source: "levels-images/9.png" 119 | on_release: app.root.current="level9" 120 | ImageButton: 121 | source: "levels-images/10.png" 122 | on_release: app.root.current="level10" 123 | ImageButton: 124 | source: "levels-images/11.png" 125 | on_release: app.root.current="level11" 126 | ImageButton: 127 | source: "levels-images/12.png" 128 | on_release: app.root.current="level12" 129 | ImageButton: 130 | source: "levels-images/13.png" 131 | on_release: app.root.current="level13" 132 | ImageButton: 133 | source: "levels-images/14.png" 134 | on_release: app.root.current="level14" 135 | ImageButton: 136 | source: "levels-images/15.png" 137 | on_release: app.root.current="level15" 138 | ImageButton: 139 | source: "levels-images/16.png" 140 | on_release: app.root.current="level16" 141 | ImageButton: 142 | source: "levels-images/17.png" 143 | on_release: app.root.current="level17" 144 | ImageButton: 145 | source: "levels-images/18.png" 146 | on_release: app.root.current="level18" 147 | ImageButton: 148 | source: "levels-images/19.png" 149 | on_release: app.root.current="level19" 150 | ImageButton: 151 | source: "levels-images/20.png" 152 | on_release: app.root.current="level20" 153 | ImageButton: 154 | source: "levels-images/21.png" 155 | on_release: app.root.current="level21" 156 | ImageButton: 157 | source: "levels-images/22.png" 158 | on_release: app.root.current="level22" 159 | ImageButton: 160 | source: "levels-images/23.png" 161 | on_release: app.root.current="level23" 162 | ImageButton: 163 | source: "levels-images/24.png" 164 | on_release: app.root.current="level24" 165 | 166 | : 167 | name: "level1" 168 | on_pre_enter: app.screen_on_pre_enter(1) 169 | on_pre_leave: app.screen_on_pre_leave(1) 170 | on_enter: app.screen_on_enter(1) 171 | FloatLayout: 172 | id: layout_lvl1 173 | on_touch_down: app.touch_down_handler(1, args) 174 | canvas.before: 175 | Rectangle: 176 | pos: self.pos 177 | size: self.size 178 | source: "levels-bg/bg_lvl1.jpg" 179 | NumCollectedCoins: 180 | id: num_coins_collected_lvl1 181 | LevelNumber 182 | id: level_number_lvl1 183 | RemainingLifePercent 184 | id: remaining_life_percent_lvl1 185 | Monster: 186 | id: monster1_image_lvl1 187 | monst_anim_duration_low: 3.5 188 | monst_anim_duration_high: 4.5 189 | Character: 190 | id: character_image_lvl1 191 | 192 | : 193 | name: "level2" 194 | on_pre_enter: app.screen_on_pre_enter(2) 195 | on_pre_leave: app.screen_on_pre_leave(2) 196 | on_enter: app.screen_on_enter(2) 197 | FloatLayout: 198 | id: layout_lvl2 199 | on_touch_down: app.touch_down_handler(2, args) 200 | canvas.before: 201 | Rectangle: 202 | pos: self.pos 203 | size: self.size 204 | source: "levels-bg/bg_lvl2.jpg" 205 | NumCollectedCoins: 206 | id: num_coins_collected_lvl2 207 | LevelNumber 208 | id: level_number_lvl2 209 | RemainingLifePercent 210 | id: remaining_life_percent_lvl2 211 | Monster: 212 | id: monster1_image_lvl2 213 | monst_anim_duration_low: 2.5 214 | monst_anim_duration_high: 3.5 215 | Character: 216 | id: character_image_lvl2 217 | 218 | : 219 | name: "level3" 220 | on_pre_enter: app.screen_on_pre_enter(3) 221 | on_pre_leave: app.screen_on_pre_leave(3) 222 | on_enter: app.screen_on_enter(3) 223 | FloatLayout: 224 | id: layout_lvl3 225 | on_touch_down: app.touch_down_handler(3, args) 226 | canvas.before: 227 | Rectangle: 228 | pos: self.pos 229 | size: self.size 230 | source: "levels-bg/bg_lvl3.jpg" 231 | NumCollectedCoins: 232 | id: num_coins_collected_lvl3 233 | LevelNumber 234 | id: level_number_lvl3 235 | RemainingLifePercent 236 | id: remaining_life_percent_lvl3 237 | Monster: 238 | id: monster1_image_lvl3 239 | monst_anim_duration_low: 1.0 240 | monst_anim_duration_high: 1.5 241 | Character: 242 | id: character_image_lvl3 243 | 244 | : 245 | name: "level4" 246 | on_pre_enter: app.screen_on_pre_enter(4) 247 | on_pre_leave: app.screen_on_pre_leave(4) 248 | on_enter: app.screen_on_enter(4) 249 | FloatLayout: 250 | id: layout_lvl4 251 | on_touch_down: app.touch_down_handler(4, args) 252 | canvas.before: 253 | Rectangle: 254 | pos: self.pos 255 | size: self.size 256 | source: "levels-bg/bg_lvl4.jpg" 257 | NumCollectedCoins: 258 | id: num_coins_collected_lvl4 259 | LevelNumber 260 | id: level_number_lvl4 261 | RemainingLifePercent 262 | id: remaining_life_percent_lvl4 263 | Fire: 264 | id: fire1_lvl4 265 | fire_start_pos_hint: {'x': 1.5, 'y': 0.5} 266 | fire_end_pos_hint: {'x': -0.5, 'y': 0.5} 267 | fire_anim_duration: 2.5 268 | Monster: 269 | id: monster1_image_lvl4 270 | monst_anim_duration_low: 2.5 271 | monst_anim_duration_high: 3.5 272 | Character: 273 | id: character_image_lvl4 274 | 275 | : 276 | name: "level5" 277 | on_pre_enter: app.screen_on_pre_enter(5) 278 | on_pre_leave: app.screen_on_pre_leave(5) 279 | on_enter: app.screen_on_enter(5) 280 | FloatLayout: 281 | id: layout_lvl5 282 | on_touch_down: app.touch_down_handler(5, args) 283 | canvas.before: 284 | Rectangle: 285 | pos: self.pos 286 | size: self.size 287 | source: "levels-bg/bg_lvl5.jpg" 288 | NumCollectedCoins: 289 | id: num_coins_collected_lvl5 290 | LevelNumber 291 | id: level_number_lvl5 292 | RemainingLifePercent 293 | id: remaining_life_percent_lvl5 294 | Fire: 295 | id: fire1_lvl5 296 | fire_start_pos_hint: {'x': 1.5, 'y': 0.7} 297 | fire_end_pos_hint: {'x': -0.5, 'y': 0.7} 298 | fire_anim_duration: 3.0 299 | Fire: 300 | id: fire2_lvl5 301 | fire_start_pos_hint: {'x': 1.5, 'y': 0.3} 302 | fire_end_pos_hint: {'x': -0.5, 'y': 0.3} 303 | fire_anim_duration: 2.0 304 | Monster: 305 | id: monster1_image_lvl5 306 | monst_anim_duration_low: 1.0 307 | monst_anim_duration_high: 1.5 308 | Character: 309 | id: character_image_lvl5 310 | 311 | : 312 | name: "level6" 313 | on_pre_enter: app.screen_on_pre_enter(6) 314 | on_pre_leave: app.screen_on_pre_leave(6) 315 | on_enter: app.screen_on_enter(6) 316 | FloatLayout: 317 | id: layout_lvl6 318 | on_touch_down: app.touch_down_handler(6, args) 319 | canvas.before: 320 | Rectangle: 321 | pos: self.pos 322 | size: self.size 323 | source: "levels-bg/bg_lvl6.jpg" 324 | NumCollectedCoins: 325 | id: num_coins_collected_lvl6 326 | LevelNumber 327 | id: level_number_lvl6 328 | RemainingLifePercent 329 | id: remaining_life_percent_lvl6 330 | Fire: 331 | id: fire1_lvl6 332 | fire_start_pos_hint: {'x': 1.5, 'y': 0.8} 333 | fire_end_pos_hint: {'x': -0.5, 'y': 0.8} 334 | fire_anim_duration: 2.5 335 | Fire: 336 | id: fire2_lvl6 337 | fire_start_pos_hint: {'x': 1.5, 'y': 0.2} 338 | fire_end_pos_hint: {'x': -0.5, 'y': 0.2} 339 | fire_anim_duration: 2.0 340 | Fire: 341 | id: fire3_lvl6 342 | fire_start_pos_hint: {'x': 0.5, 'y': 1.5} 343 | fire_end_pos_hint: {'x': 0.5, 'y': -0.5} 344 | fire_anim_duration: 3.5 345 | Monster: 346 | id: monster1_image_lvl6 347 | monst_anim_duration_low: 2.5 348 | monst_anim_duration_high: 3.0 349 | Character: 350 | id: character_image_lvl6 351 | 352 | : 353 | name: "level7" 354 | on_pre_enter: app.screen_on_pre_enter(7) 355 | on_pre_leave: app.screen_on_pre_leave(7) 356 | on_enter: app.screen_on_enter(7) 357 | FloatLayout: 358 | id: layout_lvl7 359 | on_touch_down: app.touch_down_handler(7, args) 360 | canvas.before: 361 | Rectangle: 362 | pos: self.pos 363 | size: self.size 364 | source: "levels-bg/bg_lvl7.jpg" 365 | NumCollectedCoins: 366 | id: num_coins_collected_lvl7 367 | LevelNumber 368 | id: level_number_lvl7 369 | RemainingLifePercent 370 | id: remaining_life_percent_lvl7 371 | Monster: 372 | id: monster1_image_lvl7 373 | monst_anim_duration_low: 1.0 374 | monst_anim_duration_high: 1.5 375 | Monster: 376 | id: monster2_image_lvl7 377 | monst_anim_duration_low: 1.5 378 | monst_anim_duration_high: 2.5 379 | Monster: 380 | id: monster3_image_lvl7 381 | monst_anim_duration_low: 1.5 382 | monst_anim_duration_high: 2.5 383 | Character: 384 | id: character_image_lvl7 385 | 386 | : 387 | name: "level8" 388 | on_pre_enter: app.screen_on_pre_enter(8) 389 | on_pre_leave: app.screen_on_pre_leave(8) 390 | on_enter: app.screen_on_enter(8) 391 | FloatLayout: 392 | id: layout_lvl8 393 | on_touch_down: app.touch_down_handler(8, args) 394 | canvas.before: 395 | Rectangle: 396 | pos: self.pos 397 | size: self.size 398 | source: "levels-bg/bg_lvl8.jpg" 399 | NumCollectedCoins: 400 | id: num_coins_collected_lvl8 401 | LevelNumber 402 | id: level_number_lvl8 403 | RemainingLifePercent 404 | id: remaining_life_percent_lvl8 405 | Monster: 406 | id: monster1_image_lvl8 407 | monst_anim_duration_low: 1.5 408 | monst_anim_duration_high: 2.5 409 | Monster: 410 | id: monster2_image_lvl8 411 | monst_anim_duration_low: 1.0 412 | monst_anim_duration_high: 1.5 413 | Character: 414 | id: character_image_lvl8 415 | 416 | : 417 | name: "level9" 418 | on_pre_enter: app.screen_on_pre_enter(9) 419 | on_pre_leave: app.screen_on_pre_leave(9) 420 | on_enter: app.screen_on_enter(9) 421 | FloatLayout: 422 | id: layout_lvl9 423 | on_touch_down: app.touch_down_handler(9, args) 424 | canvas.before: 425 | Rectangle: 426 | pos: self.pos 427 | size: self.size 428 | source: "levels-bg/bg_lvl9.jpg" 429 | NumCollectedCoins: 430 | id: num_coins_collected_lvl9 431 | LevelNumber 432 | id: level_number_lvl9 433 | RemainingLifePercent 434 | id: remaining_life_percent_lvl9 435 | Monster: 436 | id: monster1_image_lvl9 437 | monst_anim_duration_low: 2.5 438 | monst_anim_duration_high: 3.5 439 | Monster2: 440 | id: monster2_image_lvl9 441 | monst_anim_duration_low: 1.2 442 | monst_anim_duration_high: 1.7 443 | Character: 444 | id: character_image_lvl9 445 | 446 | : 447 | name: "level10" 448 | on_pre_enter: app.screen_on_pre_enter(10) 449 | on_pre_leave: app.screen_on_pre_leave(10) 450 | on_enter: app.screen_on_enter(10) 451 | FloatLayout: 452 | id: layout_lvl10 453 | on_touch_down: app.touch_down_handler(10, args) 454 | canvas.before: 455 | Rectangle: 456 | pos: self.pos 457 | size: self.size 458 | source: "levels-bg/bg_lvl10.jpg" 459 | NumCollectedCoins: 460 | id: num_coins_collected_lvl10 461 | LevelNumber 462 | id: level_number_lvl10 463 | RemainingLifePercent 464 | id: remaining_life_percent_lvl10 465 | Monster: 466 | id: monster1_image_lvl10 467 | monst_anim_duration_low: 1.5 468 | monst_anim_duration_high: 2.5 469 | Monster2: 470 | id: monster2_image_lvl10 471 | monst_anim_duration_low: 0.8 472 | monst_anim_duration_high: 1.2 473 | Monster2: 474 | id: monster3_image_lvl10 475 | monst_anim_duration_low: 1.0 476 | monst_anim_duration_high: 1.5 477 | Character: 478 | id: character_image_lvl10 479 | 480 | : 481 | name: "level11" 482 | on_pre_enter: app.screen_on_pre_enter(11) 483 | on_pre_leave: app.screen_on_pre_leave(11) 484 | on_enter: app.screen_on_enter(11) 485 | FloatLayout: 486 | id: layout_lvl11 487 | on_touch_down: app.touch_down_handler(11, args) 488 | canvas.before: 489 | Rectangle: 490 | pos: self.pos 491 | size: self.size 492 | source: "levels-bg/bg_lvl11.jpg" 493 | NumCollectedCoins: 494 | id: num_coins_collected_lvl11 495 | LevelNumber 496 | id: level_number_lvl11 497 | RemainingLifePercent 498 | id: remaining_life_percent_lvl11 499 | Fire: 500 | id: fire1_lvl11 501 | fire_start_pos_hint: {'x': 1.5, 'y': 0.5} 502 | fire_end_pos_hint: {'x': -0.5, 'y': 0.5} 503 | fire_anim_duration: 3.5 504 | Monster: 505 | id: monster1_image_lvl11 506 | monst_anim_duration_low: 2.5 507 | monst_anim_duration_high: 3.5 508 | Monster2: 509 | id: monster2_image_lvl11 510 | monst_anim_duration_low: 2.0 511 | monst_anim_duration_high: 2.5 512 | Character: 513 | id: character_image_lvl11 514 | 515 | : 516 | name: "level12" 517 | on_pre_enter: app.screen_on_pre_enter(12) 518 | on_pre_leave: app.screen_on_pre_leave(12) 519 | on_enter: app.screen_on_enter(12) 520 | FloatLayout: 521 | id: layout_lvl12 522 | on_touch_down: app.touch_down_handler(12, args) 523 | canvas.before: 524 | Rectangle: 525 | pos: self.pos 526 | size: self.size 527 | source: "levels-bg/bg_lvl12.jpg" 528 | NumCollectedCoins: 529 | id: num_coins_collected_lvl12 530 | LevelNumber 531 | id: level_number_lvl12 532 | RemainingLifePercent 533 | id: remaining_life_percent_lvl12 534 | Fire: 535 | id: fire1_lvl12 536 | fire_start_pos_hint: {'x': 1.5, 'y': 0.5} 537 | fire_end_pos_hint: {'x': -0.5, 'y': 0.5} 538 | fire_anim_duration: 2.5 539 | Monster: 540 | id: monster1_image_lvl12 541 | monst_anim_duration_low: 2.5 542 | monst_anim_duration_high: 3.5 543 | Monster2: 544 | id: monster2_image_lvl12 545 | monst_anim_duration_low: 1.5 546 | monst_anim_duration_high: 2.0 547 | Character: 548 | id: character_image_lvl12 549 | 550 | : 551 | name: "level13" 552 | on_pre_enter: app.screen_on_pre_enter(13) 553 | on_pre_leave: app.screen_on_pre_leave(13) 554 | on_enter: app.screen_on_enter(13) 555 | FloatLayout: 556 | id: layout_lvl13 557 | on_touch_down: app.touch_down_handler(13, args) 558 | canvas.before: 559 | Rectangle: 560 | pos: self.pos 561 | size: self.size 562 | source: "levels-bg/bg_lvl13.jpg" 563 | NumCollectedCoins: 564 | id: num_coins_collected_lvl13 565 | LevelNumber 566 | id: level_number_lvl13 567 | RemainingLifePercent 568 | id: remaining_life_percent_lvl13 569 | Fire: 570 | id: fire1_lvl13 571 | fire_start_pos_hint: {'x': 1.5, 'y': 0.5} 572 | fire_end_pos_hint: {'x': -0.5, 'y': 0.5} 573 | fire_anim_duration: 2.5 574 | Fire: 575 | id: fire2_lvl13 576 | fire_start_pos_hint: {'x': 0.5, 'y': 1.5} 577 | fire_end_pos_hint: {'x': 0.5, 'y': -0.5} 578 | fire_anim_duration: 3.5 579 | Monster: 580 | id: monster1_image_lvl13 581 | monst_anim_duration_low: 2.5 582 | monst_anim_duration_high: 3.5 583 | Monster2: 584 | id: monster2_image_lvl13 585 | monst_anim_duration_low: 2.5 586 | monst_anim_duration_high: 3.0 587 | Character: 588 | id: character_image_lvl13 589 | 590 | : 591 | name: "level14" 592 | on_pre_enter: app.screen_on_pre_enter(14) 593 | on_pre_leave: app.screen_on_pre_leave(14) 594 | on_enter: app.screen_on_enter(14) 595 | FloatLayout: 596 | id: layout_lvl14 597 | on_touch_down: app.touch_down_handler(14, args) 598 | canvas.before: 599 | Rectangle: 600 | pos: self.pos 601 | size: self.size 602 | source: "levels-bg/bg_lvl14.jpg" 603 | NumCollectedCoins: 604 | id: num_coins_collected_lvl14 605 | LevelNumber 606 | id: level_number_lvl14 607 | RemainingLifePercent 608 | id: remaining_life_percent_lvl14 609 | Fire: 610 | id: fire1_lvl14 611 | fire_start_pos_hint: {'x': 1.5, 'y': 0.2} 612 | fire_end_pos_hint: {'x': -0.5, 'y': 0.2} 613 | fire_anim_duration: 2.5 614 | Fire: 615 | id: fire2_lvl14 616 | fire_start_pos_hint: {'x': 1.5, 'y': 0.8} 617 | fire_end_pos_hint: {'x': -0.5, 'y': 0.8} 618 | fire_anim_duration: 3.5 619 | Fire: 620 | id: fire3_lvl14 621 | fire_start_pos_hint: {'x': -1.5, 'y': 0.5} 622 | fire_end_pos_hint: {'x': -0.5, 'y': 0.5} 623 | fire_anim_duration: 3.5 624 | Fire: 625 | id: fire4_lvl14 626 | fire_start_pos_hint: {'x': 0.8, 'y': 1.5} 627 | fire_end_pos_hint: {'x': 0.8, 'y': -0.5} 628 | fire_anim_duration: 2.5 629 | Fire: 630 | id: fire5_lvl14 631 | fire_start_pos_hint: {'x': 0.2, 'y': 1.5} 632 | fire_end_pos_hint: {'x': 0.2, 'y': -0.5} 633 | fire_anim_duration: 3.5 634 | Fire: 635 | id: fire6_lvl14 636 | fire_start_pos_hint: {'x': 0.5, 'y': 1.5} 637 | fire_end_pos_hint: {'x': 0.5, 'y': -0.5} 638 | fire_anim_duration: 2.5 639 | Character: 640 | id: character_image_lvl14 641 | 642 | : 643 | name: "level15" 644 | on_pre_enter: app.screen_on_pre_enter(15) 645 | on_pre_leave: app.screen_on_pre_leave(15) 646 | on_enter: app.screen_on_enter(15) 647 | FloatLayout: 648 | id: layout_lvl15 649 | on_touch_down: app.touch_down_handler(15, args) 650 | canvas.before: 651 | Rectangle: 652 | pos: self.pos 653 | size: self.size 654 | source: "levels-bg/bg_lvl15.jpg" 655 | NumCollectedCoins: 656 | id: num_coins_collected_lvl15 657 | LevelNumber 658 | id: level_number_lvl15 659 | RemainingLifePercent 660 | id: remaining_life_percent_lvl15 661 | Fire: 662 | id: fire1_lvl15 663 | fire_start_pos_hint: {'x': 1.2, 'y': 0.2} 664 | fire_end_pos_hint: {'x': -0.5, 'y': 0.2} 665 | fire_anim_duration: 2.5 666 | Fire: 667 | id: fire2_lvl15 668 | fire_start_pos_hint: {'x': 1.5, 'y': 0.7} 669 | fire_end_pos_hint: {'x': -0.5, 'y': 0.7} 670 | fire_anim_duration: 3.5 671 | Fire: 672 | id: fire3_lvl15 673 | fire_start_pos_hint: {'x': 0.5, 'y': 1.5} 674 | fire_end_pos_hint: {'x': 0.5, 'y': -0.5} 675 | fire_anim_duration: 2.5 676 | Monster2: 677 | id: monster1_image_lvl15 678 | monst_anim_duration_low: 3.0 679 | monst_anim_duration_high: 3.5 680 | Monster2: 681 | id: monster2_image_lvl15 682 | monst_anim_duration_low: 3.0 683 | monst_anim_duration_high: 3.5 684 | Character: 685 | id: character_image_lvl15 686 | 687 | : 688 | name: "level16" 689 | on_pre_enter: app.screen_on_pre_enter(16) 690 | on_pre_leave: app.screen_on_pre_leave(16) 691 | on_enter: app.screen_on_enter(16) 692 | FloatLayout: 693 | id: layout_lvl16 694 | on_touch_down: app.touch_down_handler(16, args) 695 | canvas.before: 696 | Rectangle: 697 | pos: self.pos 698 | size: self.size 699 | source: "levels-bg/bg_lvl16.jpg" 700 | NumCollectedCoins: 701 | id: num_coins_collected_lvl16 702 | LevelNumber 703 | id: level_number_lvl16 704 | RemainingLifePercent 705 | id: remaining_life_percent_lvl16 706 | Fire: 707 | id: fire1_lvl16 708 | fire_start_pos_hint: {'x': 1.5, 'y': 0.2} 709 | fire_end_pos_hint: {'x': -0.5, 'y': 0.2} 710 | fire_anim_duration: 2.5 711 | Fire: 712 | id: fire2_lvl16 713 | fire_start_pos_hint: {'x': 1.5, 'y': 0.7} 714 | fire_end_pos_hint: {'x': -0.5, 'y': 0.7} 715 | fire_anim_duration: 1.5 716 | Monster: 717 | id: monster1_image_lvl16 718 | monst_anim_duration_low: 2.0 719 | monst_anim_duration_high: 3.5 720 | Monster2: 721 | id: monster2_image_lvl16 722 | monst_anim_duration_low: 3.0 723 | monst_anim_duration_high: 3.5 724 | Monster2: 725 | id: monster3_image_lvl16 726 | monst_anim_duration_low: 1.0 727 | monst_anim_duration_high: 1.5 728 | Character: 729 | id: character_image_lvl16 730 | 731 | : 732 | name: "level17" 733 | on_pre_enter: app.screen_on_pre_enter(17) 734 | on_pre_leave: app.screen_on_pre_leave(17) 735 | on_enter: app.screen_on_enter(17) 736 | FloatLayout: 737 | id: layout_lvl17 738 | on_touch_down: app.touch_down_handler(17, args) 739 | canvas.before: 740 | Rectangle: 741 | pos: self.pos 742 | size: self.size 743 | source: "levels-bg/bg_lvl17.jpg" 744 | NumCollectedCoins: 745 | id: num_coins_collected_lvl17 746 | LevelNumber 747 | id: level_number_lvl17 748 | RemainingLifePercent 749 | id: remaining_life_percent_lvl17 750 | Fire: 751 | id: fire1_lvl17 752 | fire_start_pos_hint: {'x': 1.5, 'y': 0.3} 753 | fire_end_pos_hint: {'x': -1.5, 'y': 0.3} 754 | fire_anim_duration: 1.5 755 | Fire: 756 | id: fire2_lvl17 757 | fire_start_pos_hint: {'x': 1.5, 'y': 0.8} 758 | fire_end_pos_hint: {'x': -1.5, 'y': 0.8} 759 | fire_anim_duration: 1.0 760 | Fire: 761 | id: fire3_lvl17 762 | fire_start_pos_hint: {'x': 0.8, 'y': -1.5} 763 | fire_end_pos_hint: {'x': 0.8, 'y': 1.5} 764 | fire_anim_duration: 1.5 765 | Fire: 766 | id: fire4_lvl17 767 | fire_start_pos_hint: {'x': 0.3, 'y': 1.5} 768 | fire_end_pos_hint: {'x': 0.3, 'y': -1.5} 769 | fire_anim_duration: 1.0 770 | Character: 771 | id: character_image_lvl17 772 | 773 | : 774 | name: "level18" 775 | on_pre_enter: app.screen_on_pre_enter(18) 776 | on_pre_leave: app.screen_on_pre_leave(18) 777 | on_enter: app.screen_on_enter(18) 778 | FloatLayout: 779 | id: layout_lvl18 780 | on_touch_down: app.touch_down_handler(18, args) 781 | canvas.before: 782 | Rectangle: 783 | pos: self.pos 784 | size: self.size 785 | source: "levels-bg/bg_lvl18.jpg" 786 | NumCollectedCoins: 787 | id: num_coins_collected_lvl18 788 | LevelNumber 789 | id: level_number_lvl18 790 | RemainingLifePercent 791 | id: remaining_life_percent_lvl18 792 | Fire: 793 | id: fire1_lvl18 794 | fire_start_pos_hint: {'x': 0.8, 'y': 0.3} 795 | fire_end_pos_hint: {'x': 0.2, 'y': 0.3} 796 | fire_anim_duration: 1.2 797 | Fire: 798 | id: fire2_lvl18 799 | fire_start_pos_hint: {'x': 0.3, 'y': 0.8} 800 | fire_end_pos_hint: {'x': 0.7, 'y': 0.8} 801 | fire_anim_duration: 1.3 802 | Fire: 803 | id: fire3_lvl18 804 | fire_start_pos_hint: {'x': 0.8, 'y': 0.3} 805 | fire_end_pos_hint: {'x': 0.8, 'y': 0.7} 806 | fire_anim_duration: 1.2 807 | Fire: 808 | id: fire4_lvl18 809 | fire_start_pos_hint: {'x': 0.3, 'y': 0.8} 810 | fire_end_pos_hint: {'x': 0.3, 'y': 0.2} 811 | fire_anim_duration: 1.0 812 | Monster: 813 | id: monster1_image_lvl18 814 | monst_anim_duration_low: 1.0 815 | monst_anim_duration_high: 1.6 816 | Monster2: 817 | id: monster2_image_lvl18 818 | monst_anim_duration_low: 1.0 819 | monst_anim_duration_high: 2.0 820 | Monster2: 821 | id: monster3_image_lvl18 822 | monst_anim_duration_low: 1.0 823 | monst_anim_duration_high: 1.2 824 | Character: 825 | id: character_image_lvl18 826 | 827 | : 828 | name: "level19" 829 | on_pre_enter: app.screen_on_pre_enter(19) 830 | on_pre_leave: app.screen_on_pre_leave(19) 831 | on_enter: app.screen_on_enter(19) 832 | FloatLayout: 833 | id: layout_lvl19 834 | on_touch_down: app.touch_down_handler(19, args) 835 | canvas.before: 836 | Rectangle: 837 | pos: self.pos 838 | size: self.size 839 | source: "levels-bg/bg_lvl19.jpg" 840 | NumCollectedCoins: 841 | id: num_coins_collected_lvl19 842 | LevelNumber 843 | id: level_number_lvl19 844 | RemainingLifePercent 845 | id: remaining_life_percent_lvl19 846 | Fire: 847 | id: fire1_lvl19 848 | fire_start_pos_hint: {'x': 0.8, 'y': 0.3} 849 | fire_end_pos_hint: {'x': 0.2, 'y': 0.3} 850 | fire_anim_duration: 1.2 851 | Fire: 852 | id: fire2_lvl19 853 | fire_start_pos_hint: {'x': 0.3, 'y': 0.8} 854 | fire_end_pos_hint: {'x': 0.7, 'y': 0.8} 855 | fire_anim_duration: 1.0 856 | Fire: 857 | id: fire3_lvl19 858 | fire_start_pos_hint: {'x': -1.5, 'y': 0.5} 859 | fire_end_pos_hint: {'x': 1.5, 'y': 0.5} 860 | fire_anim_duration: 1.5 861 | Fire: 862 | id: fire4_lvl19 863 | fire_start_pos_hint: {'x': 0.8, 'y': 0.3} 864 | fire_end_pos_hint: {'x': 0.8, 'y': 0.7} 865 | fire_anim_duration: 1.2 866 | Fire: 867 | id: fire5_lvl19 868 | fire_start_pos_hint: {'x': 0.3, 'y': 0.8} 869 | fire_end_pos_hint: {'x': 0.3, 'y': 0.2} 870 | fire_anim_duration: 1.3 871 | Fire: 872 | id: fire6_lvl19 873 | fire_start_pos_hint: {'x': 0.5, 'y': -1.5} 874 | fire_end_pos_hint: {'x': 0.5, 'y': 1.5} 875 | fire_anim_duration: 1.4 876 | Character: 877 | id: character_image_lvl19 878 | 879 | : 880 | name: "level20" 881 | on_pre_enter: app.screen_on_pre_enter(20) 882 | on_pre_leave: app.screen_on_pre_leave(20) 883 | on_enter: app.screen_on_enter(20) 884 | FloatLayout: 885 | id: layout_lvl20 886 | on_touch_down: app.touch_down_handler(20, args) 887 | canvas.before: 888 | Rectangle: 889 | pos: self.pos 890 | size: self.size 891 | source: "levels-bg/bg_lvl20.jpg" 892 | NumCollectedCoins: 893 | id: num_coins_collected_lvl20 894 | LevelNumber 895 | id: level_number_lvl20 896 | RemainingLifePercent 897 | id: remaining_life_percent_lvl20 898 | Fire: 899 | id: fire1_lvl20 900 | fire_start_pos_hint: {'x': 0.8, 'y': 0.3} 901 | fire_end_pos_hint: {'x': 0.2, 'y': 0.3} 902 | fire_anim_duration: 1.5 903 | Fire: 904 | id: fire2_lvl20 905 | fire_start_pos_hint: {'x': 0.3, 'y': 0.8} 906 | fire_end_pos_hint: {'x': 0.7, 'y': 0.8} 907 | fire_anim_duration: 1.3 908 | Fire: 909 | id: fire3_lvl20 910 | fire_start_pos_hint: {'x': -1.5, 'y': 0.5} 911 | fire_end_pos_hint: {'x': 1.5, 'y': 0.5} 912 | fire_anim_duration: 1.6 913 | Fire: 914 | id: fire4_lvl20 915 | fire_start_pos_hint: {'x': 0.1, 'y': 0.3} 916 | fire_end_pos_hint: {'x': 0.9, 'y': 0.3} 917 | fire_anim_duration: 1.5 918 | Fire: 919 | id: fire5_lvl20 920 | fire_start_pos_hint: {'x': 0.8, 'y': 0.3} 921 | fire_end_pos_hint: {'x': 0.8, 'y': 0.7} 922 | fire_anim_duration: 1.5 923 | Fire: 924 | id: fire6_lvl20 925 | fire_start_pos_hint: {'x': 0.3, 'y': 0.8} 926 | fire_end_pos_hint: {'x': 0.3, 'y': 0.2} 927 | fire_anim_duration: 1.3 928 | Fire: 929 | id: fire7_lvl20 930 | fire_start_pos_hint: {'x': 0.5, 'y': -1.5} 931 | fire_end_pos_hint: {'x': 0.5, 'y': 1.5} 932 | fire_anim_duration: 1.6 933 | Fire: 934 | id: fire8_lvl20 935 | fire_start_pos_hint: {'x': 0.5, 'y': 0.1} 936 | fire_end_pos_hint: {'x': 0.5, 'y': 0.9} 937 | fire_anim_duration: 1.3 938 | Character: 939 | id: character_image_lvl20 940 | 941 | : 942 | name: "level21" 943 | on_pre_enter: app.screen_on_pre_enter(21) 944 | on_pre_leave: app.screen_on_pre_leave(21) 945 | on_enter: app.screen_on_enter(21) 946 | FloatLayout: 947 | id: layout_lvl21 948 | on_touch_down: app.touch_down_handler(21, args) 949 | canvas.before: 950 | Rectangle: 951 | pos: self.pos 952 | size: self.size 953 | source: "levels-bg/bg_lvl1.jpg" 954 | NumCollectedCoins: 955 | id: num_coins_collected_lvl21 956 | LevelNumber 957 | id: level_number_lvl21 958 | RemainingLifePercent 959 | id: remaining_life_percent_lvl21 960 | Fire: 961 | id: fire1_lvl21 962 | fire_start_pos_hint: {'x': 0.8, 'y': 0.3} 963 | fire_end_pos_hint: {'x': 0.2, 'y': 0.3} 964 | fire_anim_duration: 1.8 965 | Fire: 966 | id: fire2_lvl21 967 | fire_start_pos_hint: {'x': 0.3, 'y': 0.8} 968 | fire_end_pos_hint: {'x': 0.7, 'y': 0.8} 969 | fire_anim_duration: 1.5 970 | Fire: 971 | id: fire3_lvl21 972 | fire_start_pos_hint: {'x': -1.5, 'y': 0.5} 973 | fire_end_pos_hint: {'x': 1.5, 'y': 0.5} 974 | fire_anim_duration: 2.0 975 | Fire: 976 | id: fire4_lvl21 977 | fire_start_pos_hint: {'x': 0.1, 'y': 0.3} 978 | fire_end_pos_hint: {'x': 0.9, 'y': 0.3} 979 | fire_anim_duration: 2.5 980 | Monster: 981 | id: monster1_image_lvl21 982 | monst_anim_duration_low: 1.0 983 | monst_anim_duration_high: 1.3 984 | Monster2: 985 | id: monster2_image_lvl21 986 | monst_anim_duration_low: 1.0 987 | monst_anim_duration_high: 1.5 988 | Character: 989 | id: character_image_lvl21 990 | 991 | : 992 | name: "level22" 993 | on_pre_enter: app.screen_on_pre_enter(22) 994 | on_pre_leave: app.screen_on_pre_leave(22) 995 | on_enter: app.screen_on_enter(22) 996 | FloatLayout: 997 | id: layout_lvl22 998 | on_touch_down: app.touch_down_handler(22, args) 999 | canvas.before: 1000 | Rectangle: 1001 | pos: self.pos 1002 | size: self.size 1003 | source: "levels-bg/bg_lvl2.jpg" 1004 | NumCollectedCoins: 1005 | id: num_coins_collected_lvl22 1006 | LevelNumber 1007 | id: level_number_lvl22 1008 | RemainingLifePercent 1009 | id: remaining_life_percent_lvl22 1010 | Fire: 1011 | id: fire1_lvl22 1012 | fire_start_pos_hint: {'x': 0.8, 'y': 0.3} 1013 | fire_end_pos_hint: {'x': 0.2, 'y': 0.3} 1014 | fire_anim_duration: 1.9 1015 | Fire: 1016 | id: fire2_lvl22 1017 | fire_start_pos_hint: {'x': 0.3, 'y': 0.8} 1018 | fire_end_pos_hint: {'x': 0.7, 'y': 0.8} 1019 | fire_anim_duration: 2.0 1020 | Fire: 1021 | id: fire3_lvl22 1022 | fire_start_pos_hint: {'x': -1.5, 'y': 0.5} 1023 | fire_end_pos_hint: {'x': 1.5, 'y': 0.5} 1024 | fire_anim_duration: 2.0 1025 | Fire: 1026 | id: fire4_lvl22 1027 | fire_start_pos_hint: {'x': 0.1, 'y': 0.3} 1028 | fire_end_pos_hint: {'x': 0.9, 'y': 0.3} 1029 | fire_anim_duration: 2.5 1030 | Monster: 1031 | id: monster1_image_lvl22 1032 | monst_anim_duration_low: 1.0 1033 | monst_anim_duration_high: 1.8 1034 | Monster2: 1035 | id: monster2_image_lvl22 1036 | monst_anim_duration_low: 1.0 1037 | monst_anim_duration_high: 2.0 1038 | Character: 1039 | id: character_image_lvl22 1040 | 1041 | : 1042 | name: "level23" 1043 | on_pre_enter: app.screen_on_pre_enter(23) 1044 | on_pre_leave: app.screen_on_pre_leave(23) 1045 | on_enter: app.screen_on_enter(23) 1046 | FloatLayout: 1047 | id: layout_lvl23 1048 | on_touch_down: app.touch_down_handler(23, args) 1049 | canvas.before: 1050 | Rectangle: 1051 | pos: self.pos 1052 | size: self.size 1053 | source: "levels-bg/bg_lvl3.jpg" 1054 | NumCollectedCoins: 1055 | id: num_coins_collected_lvl23 1056 | LevelNumber 1057 | id: level_number_lvl23 1058 | RemainingLifePercent 1059 | id: remaining_life_percent_lvl23 1060 | Fire: 1061 | id: fire1_lvl23 1062 | fire_start_pos_hint: {'x': -1.5, 'y': 0.3} 1063 | fire_end_pos_hint: {'x': -0.5, 'y': 0.3} 1064 | fire_anim_duration: 1.8 1065 | Fire: 1066 | id: fire2_lvl23 1067 | fire_start_pos_hint: {'x': -1.5, 'y': 0.8} 1068 | fire_end_pos_hint: {'x': -0.5, 'y': 0.8} 1069 | fire_anim_duration: 2.0 1070 | Monster: 1071 | id: monster1_image_lvl23 1072 | monst_anim_duration_low: 1.5 1073 | monst_anim_duration_high: 2.0 1074 | Monster2: 1075 | id: monster2_image_lvl23 1076 | monst_anim_duration_low: 1.5 1077 | monst_anim_duration_high: 2.5 1078 | Character: 1079 | id: character_image_lvl23 1080 | 1081 | : 1082 | name: "level24" 1083 | on_pre_enter: app.screen_on_pre_enter(24) 1084 | on_pre_leave: app.screen_on_pre_leave(24) 1085 | on_enter: app.screen_on_enter(24) 1086 | FloatLayout: 1087 | id: layout_lvl24 1088 | on_touch_down: app.touch_down_handler(24, args) 1089 | canvas.before: 1090 | Rectangle: 1091 | pos: self.pos 1092 | size: self.size 1093 | source: "levels-bg/bg_lvl4.jpg" 1094 | NumCollectedCoins: 1095 | id: num_coins_collected_lvl24 1096 | LevelNumber 1097 | id: level_number_lvl24 1098 | RemainingLifePercent 1099 | id: remaining_life_percent_lvl24 1100 | Fire: 1101 | id: fire1_lvl24 1102 | fire_start_pos_hint: {'x': 0.8, 'y': 0.3} 1103 | fire_end_pos_hint: {'x': 0.2, 'y': 0.3} 1104 | fire_anim_duration: 1.8 1105 | Fire: 1106 | id: fire2_lvl24 1107 | fire_start_pos_hint: {'x': 0.3, 'y': 0.8} 1108 | fire_end_pos_hint: {'x': 0.7, 'y': 0.8} 1109 | fire_anim_duration: 1.5 1110 | Monster: 1111 | id: monster1_image_lvl24 1112 | monst_anim_duration_low: 1.5 1113 | monst_anim_duration_high: 1.7 1114 | Monster2: 1115 | id: monster2_image_lvl24 1116 | monst_anim_duration_low: 1.8 1117 | monst_anim_duration_high: 2.5 1118 | Monster: 1119 | id: monster3_image_lvl24 1120 | monst_anim_duration_low: 1.5 1121 | monst_anim_duration_high: 2.0 1122 | Character: 1123 | id: character_image_lvl24 1124 | 1125 | : 1126 | size_hint: (0.1, 0.02) 1127 | pos_hint: {'x': 0.026, 'y': 0.97} 1128 | text: "Coins 0" 1129 | font_size: 20 1130 | 1131 | : 1132 | size_hint: (0.1, 0.02) 1133 | pos_hint: {'x': 0.15, 'y': 0.97} 1134 | text: "Level" 1135 | font_size: 20 1136 | 1137 | : 1138 | remaining_life_size_hint_x: 0.2 1139 | size_hint: (0.2, 0.022) 1140 | pos_hint: {'x': 0.3, 'y': 0.97} 1141 | font_size: 20 1142 | canvas: 1143 | Color: 1144 | rgb: (1, 0, 0) 1145 | Rectangle: 1146 | pos: self.pos 1147 | size: self.size 1148 | 1149 | : 1150 | size_hint: (0.15, 0.15) 1151 | pos_hint: {'x': 0.8, 'y': 0.8} 1152 | source: "10.png" 1153 | im_num: 10 1154 | start_im_num: 10 1155 | end_im_num: 17 1156 | allow_stretch: True 1157 | on_im_num: app.change_monst_im(self) 1158 | on_pos_hint: app.monst_pos_hint(self) 1159 | 1160 | : 1161 | size_hint: (0.15, 0.15) 1162 | pos_hint: {'x': 0.8, 'y': 0.8} 1163 | source: "21.png" 1164 | im_num: 21 1165 | start_im_num: 21 1166 | end_im_num: 29 1167 | allow_stretch: True 1168 | on_im_num: app.change_monst_im(self) 1169 | on_pos_hint: app.monst_pos_hint(self) 1170 | 1171 | : 1172 | size_hint: (0.15, 0.15) 1173 | pos_hint: {'x': 0.0, 'y': 0.0} 1174 | source: "0.png" 1175 | im_num: 0 1176 | start_im_num: 0 1177 | end_im_num: 7 1178 | dead_start_im_num: 91 1179 | dead_end_im_num: 95 1180 | allow_stretch: True 1181 | on_im_num: app.change_char_im(self) 1182 | on_pos_hint: app.char_pos_hint(self) 1183 | 1184 | : 1185 | pos_hint: {'x': 1.1, 'y': 1.1} 1186 | on_pos_hint: app.fire_pos_hint(self) 1187 | size_hint: (0.03, 0.03) 1188 | canvas: 1189 | Rectangle: 1190 | pos: self.pos 1191 | size: self.size 1192 | source: "fire.png" 1193 | 1194 | : 1195 | canvas.before: 1196 | Color: 1197 | rgba: (0.6, 0.6, 0.6, 0.5) 1198 | Rectangle: 1199 | pos: self.pos 1200 | size: self.size 1201 | 1202 | -------------------------------------------------------------------------------- /Ch07/1.AudioApp/audio.kv: -------------------------------------------------------------------------------- 1 | BoxLayout: 2 | orientation: "vertical" 3 | Label: 4 | id: audio_pos 5 | size_hint_x: 0.0 6 | size: (0.0, 0.0) 7 | canvas.before: 8 | Color: 9 | rgb: (1, 0, 0) 10 | Rectangle: 11 | pos: self.pos 12 | size: self.size 13 | Label: 14 | font_size: 20 15 | id: audio_pos_info 16 | text: "Audio Position Info" 17 | Button: 18 | text: "Play" 19 | on_release: app.start_audio() 20 | Button: 21 | text: "Pause" 22 | on_release: app.pause_audio() 23 | Button: 24 | text: "Stop" 25 | on_release: app.stop_audio() 26 | -------------------------------------------------------------------------------- /Ch07/1.AudioApp/bg_music_piano.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch07/1.AudioApp/bg_music_piano.wav -------------------------------------------------------------------------------- /Ch07/1.AudioApp/buildozer.spec: -------------------------------------------------------------------------------- 1 | [app] 2 | 3 | # (str) Title of your application 4 | title = TestPlyer 5 | 6 | # (str) Package name 7 | package.name = addnum 8 | 9 | # (str) Package domain (needed for android/ios packaging) 10 | package.domain = com.gad 11 | 12 | # (str) Source code where the main.py live 13 | source.dir = . 14 | 15 | # (list) Source files to include (let empty to include all the files) 16 | source.include_exts = py,png,jpg,kv,atlas,wav 17 | 18 | # (list) List of inclusions using pattern matching 19 | #source.include_patterns = assets/*,images/*.png 20 | 21 | # (list) Source files to exclude (let empty to not exclude anything) 22 | #source.exclude_exts = spec 23 | 24 | # (list) List of directory to exclude (let empty to not exclude anything) 25 | source.exclude_dirs = temp, bin 26 | 27 | # (list) List of exclusions using pattern matching 28 | #source.exclude_patterns = license,images/*/*.jpg 29 | 30 | # (str) Application versioning (method 1) 31 | version = 0.1 32 | 33 | # (str) Application versioning (method 2) 34 | # version.regex = __version__ = ['"](.*)['"] 35 | # version.filename = %(source.dir)s/main.py 36 | 37 | # (list) Application requirements 38 | # comma separated e.g. requirements = sqlite3,kivy 39 | requirements = kivy,pyjnius 40 | #bootstrap = sdl2, pygame, opencv 41 | #requirements = plyer,kivy,opencv,numpy,pyjnius,ffmpeg, sqlite3, openssl 42 | #requirements.source.numpy = /home/ahmedgad/Desktop/numpy15 43 | 44 | # (str) Custom source folders for requirements 45 | # Sets custom source for any requirements with recipes 46 | # requirements.source.kivy = ../../kivy 47 | 48 | # (list) Garden requirements 49 | #garden_requirements = 50 | 51 | # (str) Presplash of the application 52 | presplash.filename = %(source.dir)s/presplash.png 53 | 54 | # (str) Icon of the application 55 | icon.filename = %(source.dir)s/icon.png 56 | 57 | # (str) Supported orientation (one of landscape, portrait or all) 58 | orientation = portrait 59 | 60 | # (list) List of service to declare 61 | #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY 62 | 63 | # 64 | # OSX Specific 65 | # 66 | 67 | # 68 | # author = © Copyright Info 69 | 70 | # change the major version of python used by the app 71 | osx.python_version = 3 72 | 73 | # Kivy version to use 74 | #osx.kivy_version = 1.9.1 75 | 76 | # 77 | # Android specific 78 | # 79 | 80 | # (bool) Indicate if the application should be fullscreen or not 81 | fullscreen = 0 82 | 83 | # (string) Presplash background color (for new android toolchain) 84 | # Supported formats are: #RRGGBB #AARRGGBB or one of the following names: 85 | # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, 86 | # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, 87 | # olive, purple, silver, teal. 88 | #android.presplash_color = #FFFFFF 89 | 90 | # (list) Permissions 91 | android.permissions = CAMERA 92 | 93 | # (int) Android API to use 94 | android.api = 27 95 | 96 | # (int) Minimum API required 97 | android.minapi = 19 98 | 99 | # (int) Android SDK version to use 100 | android.sdk = 27 101 | 102 | # (str) Android NDK version to use 103 | #android.ndk = 9c 104 | 105 | # (bool) Use --private data storage (True) or --dir public storage (False) 106 | #android.private_storage = True 107 | 108 | # (str) Android NDK directory (if empty, it will be automatically downloaded.) 109 | android.ndk_path = /home/ahmedgad/.buildozer/android/platform/android-ndk-r16b 110 | 111 | # (str) Android SDK directory (if empty, it will be automatically downloaded.) 112 | android.sdk_path = /home/ahmedgad/.buildozer/android/platform/android-sdk-linux 113 | 114 | # (str) Android NDK directory (if empty, it will be automatically downloaded.) 115 | #android.ndk_path = 116 | 117 | # (str) Android SDK directory (if empty, it will be automatically downloaded.) 118 | #android.sdk_path = 119 | 120 | # (str) ANT directory (if empty, it will be automatically downloaded.) 121 | #android.ant_path = /home/ahmedgad/.buildozer/android/platform/android-sdk-linux/apache-ant-1.9.4 122 | 123 | # (str) ANT directory (if empty, it will be automatically downloaded.) 124 | #android.ant_path = 125 | 126 | # (bool) If True, then skip trying to update the Android sdk 127 | # This can be useful to avoid excess Internet downloads or save time 128 | # when an update is due and you just want to test/build your package 129 | # android.skip_update = False 130 | 131 | # (str) Android entry point, default is ok for Kivy-based app 132 | #android.entrypoint = org.renpy.android.PythonActivity 133 | 134 | # (list) Pattern to whitelist for the whole project 135 | #android.whitelist = 136 | 137 | # (str) Path to a custom whitelist file 138 | #android.whitelist_src = 139 | 140 | # (str) Path to a custom blacklist file 141 | #android.blacklist_src = 142 | 143 | # (list) List of Java .jar files to add to the libs so that pyjnius can access 144 | # their classes. Don't add jars that you do not need, since extra jars can slow 145 | # down the build process. Allows wildcards matching, for example: 146 | # OUYA-ODK/libs/*.jar 147 | #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar 148 | 149 | # (list) List of Java files to add to the android project (can be java or a 150 | # directory containing the files) 151 | #android.add_src = 152 | 153 | # (list) Android AAR archives to add (currently works only with sdl2_gradle 154 | # bootstrap) 155 | #android.add_aars = 156 | 157 | # (list) Gradle dependencies to add (currently works only with sdl2_gradle 158 | # bootstrap) 159 | #android.gradle_dependencies = 160 | 161 | # (list) Java classes to add as activities to the manifest. 162 | #android.add_activites = com.example.ExampleActivity 163 | 164 | # (str) python-for-android branch to use, defaults to stable 165 | #p4a.branch = stable 166 | p4a.source_dir=/home/ahmedgad/Desktop/python-for-android 167 | 168 | #p4a.source_dir=/home/ahmedgad/Desktop/testp4a/python-for-android 169 | 170 | # (str) OUYA Console category. Should be one of GAME or APP 171 | # If you leave this blank, OUYA support will not be enabled 172 | #android.ouya.category = GAME 173 | 174 | # (str) Filename of OUYA Console icon. It must be a 732x412 png image. 175 | #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png 176 | 177 | # (str) XML file to include as an intent filters in tag 178 | #android.manifest.intent_filters = 179 | 180 | # (str) launchMode to set for the main activity 181 | #android.manifest.launch_mode = standard 182 | 183 | # (list) Android additional libraries to copy into libs/armeabi 184 | #android.add_libs_armeabi = libs/android/*.so 185 | #android.add_libs_armeabi_v7a = libs/android-v7/*.so 186 | #android.add_libs_x86 = libs/android-x86/*.so 187 | #android.add_libs_mips = libs/android-mips/*.so 188 | 189 | # (bool) Indicate whether the screen should stay on 190 | # Don't forget to add the WAKE_LOCK permission if you set this to True 191 | #android.wakelock = False 192 | 193 | # (list) Android application meta-data to set (key=value format) 194 | #android.meta_data = 195 | 196 | # (list) Android library project to add (will be added in the 197 | # project.properties automatically.) 198 | #android.library_references = 199 | 200 | # (str) Android logcat filters to use 201 | #android.logcat_filters = *:S python:D 202 | 203 | # (bool) Copy library instead of making a libpymodules.so 204 | #android.copy_libs = 1 205 | 206 | # (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86 207 | android.arch = armeabi-v7a 208 | 209 | # 210 | # Python for android (p4a) specific 211 | # 212 | 213 | # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) 214 | #p4a.source_dir = 215 | 216 | # (str) The directory in which python-for-android should look for your own build recipes (if any) 217 | #p4a.local_recipes = 218 | 219 | # (str) Filename to the hook for p4a 220 | #p4a.hook = 221 | 222 | # (str) Bootstrap to use for android builds 223 | # p4a.bootstrap = sdl2 224 | 225 | # (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask) 226 | #p4a.port = 227 | 228 | 229 | # 230 | # iOS specific 231 | # 232 | 233 | # (str) Path to a custom kivy-ios folder 234 | #ios.kivy_ios_dir = ../kivy-ios 235 | 236 | # (str) Name of the certificate to use for signing the debug version 237 | # Get a list of available identities: buildozer ios list_identities 238 | #ios.codesign.debug = "iPhone Developer: ()" 239 | 240 | # (str) Name of the certificate to use for signing the release version 241 | #ios.codesign.release = %(ios.codesign.debug)s 242 | 243 | 244 | [buildozer] 245 | 246 | # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) 247 | log_level = 2 248 | 249 | # (int) Display warning if buildozer is run as root (0 = False, 1 = True) 250 | warn_on_root = 1 251 | 252 | # (str) Path to build artifact storage, absolute or relative to spec file 253 | # build_dir = ./.buildozer 254 | 255 | # (str) Path to build output (i.e. .apk, .ipa) storage 256 | # bin_dir = ./bin 257 | 258 | # ----------------------------------------------------------------------------- 259 | # List as sections 260 | # 261 | # You can define all the "list" as [section:key]. 262 | # Each line will be considered as a option to the list. 263 | # Let's take [app] / source.exclude_patterns. 264 | # Instead of doing: 265 | # 266 | #[app] 267 | #source.exclude_patterns = license,data/audio/*.wav,data/images/original/* 268 | # 269 | # This can be translated into: 270 | # 271 | #[app:source.exclude_patterns] 272 | #license 273 | #data/audio/*.wav 274 | #data/images/original/* 275 | # 276 | 277 | 278 | # ----------------------------------------------------------------------------- 279 | # Profiles 280 | # 281 | # You can extend section / key with a profile 282 | # For example, you want to deploy a demo version of your application without 283 | # HD content. You could first change the title to add "(demo)" in the name 284 | # and extend the excluded directories to remove the HD content. 285 | # 286 | #[app@demo] 287 | #title = My Application (demo) 288 | # 289 | #[app:source.exclude_patterns@demo] 290 | #images/hd/* 291 | # 292 | # Then, invoke the command line with the "demo" profile: 293 | # 294 | #buildozer --profile demo android debug 295 | -------------------------------------------------------------------------------- /Ch07/1.AudioApp/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch07/1.AudioApp/icon.png -------------------------------------------------------------------------------- /Ch07/1.AudioApp/main.py: -------------------------------------------------------------------------------- 1 | import kivy.app 2 | import jnius 3 | import os 4 | 5 | PythonActivity = jnius.autoclass("org.kivy.android.PythonActivity") 6 | mActivity = PythonActivity.mActivity 7 | 8 | class AudioApp(kivy.app.App): 9 | prepare_audio = False 10 | 11 | def start_audio(self): 12 | if AudioApp.prepare_audio == False: 13 | MediaPlayer = jnius.autoclass("android.media.MediaPlayer") 14 | self.mediaPlayer = MediaPlayer() 15 | try: 16 | fileName = os.getcwd()+"/bg_music_piano.wav" 17 | self.mediaPlayer.setDataSource(fileName) 18 | self.mediaPlayer.prepare() 19 | 20 | kivy.clock.Clock.schedule_interval(self.update_position, 0.1) 21 | 22 | self.mediaPlayer.start() 23 | AudioApp.prepare_audio = True 24 | mActivity.toastError("Playing") 25 | except: 26 | self.current_pos.text = "Error Playing the Audio File" 27 | print("Error Playing the Audio File") 28 | mActivity.toastError("Error Playing the Audio File") 29 | else: 30 | self.mediaPlayer.start() 31 | mActivity.toastError("Playing") 32 | 33 | def pause_audio(self): 34 | if AudioApp.prepare_audio == True: 35 | self.mediaPlayer.pause() 36 | mActivity.toastError("Paused") 37 | 38 | def stop_audio(self): 39 | if AudioApp.prepare_audio == True: 40 | self.mediaPlayer.stop() 41 | mActivity.toastError("Stopped") 42 | AudioApp.prepare_audio = False 43 | 44 | def update_position(self, *args): 45 | audioDuration = self.mediaPlayer.getDuration() 46 | currentPosition = self.mediaPlayer.getCurrentPosition() 47 | pos_percent = float(currentPosition)/float(audioDuration) 48 | 49 | self.root.ids['audio_pos'].size_hint_x = pos_percent 50 | 51 | self.root.ids['audio_pos_info'].text = "Duration: "+str(audioDuration) + "\nPosition: " + str(currentPosition)+"\nPercent (%): "+str(round(pos_percent*100, 2)) 52 | 53 | app = AudioApp() 54 | app.run() 55 | 56 | -------------------------------------------------------------------------------- /Ch07/1.AudioApp/presplash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/building-android-apps-in-python-using-kivy/d63872a8296d9edfe649bdf1fd5aa31126953b56/Ch07/1.AudioApp/presplash.png -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Freeware License, some rights reserved 2 | 3 | Copyright (c) 2019 Ahmed Fawzy Mohamed Gad 4 | 5 | Permission is hereby granted, free of charge, to anyone obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to work with the Software within the limits of freeware distribution and fair use. 8 | This includes the rights to use, copy, and modify the Software for personal use. 9 | Users are also allowed and encouraged to submit corrections and modifications 10 | to the Software for the benefit of other users. 11 | 12 | It is not allowed to reuse, modify, or redistribute the Software for 13 | commercial use in any way, or for a user’s educational materials such as books 14 | or blog articles without prior permission from the copyright holder. 15 | 16 | The above copyright notice and this permission notice need to be included 17 | in all copies or substantial portions of the software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Building Android Apps in Python Using Kivy with Android Studio*](https://www.apress.com/9781484250303) by Ahmed Fawzy Mohamed Gad (Apress, 2019). 4 | 5 | [comment]: #cover 6 | ![Cover image](9781484250303.jpg) 7 | 8 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 9 | 10 | ## Releases 11 | 12 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 13 | 14 | ## Contributions 15 | 16 | See the file Contributing.md for more information on how you can contribute to this repository. -------------------------------------------------------------------------------- /errata.md: -------------------------------------------------------------------------------- 1 | # Errata for *Book Title* 2 | 3 | On **page xx** [Summary of error]: 4 | 5 | Details of error here. Highlight key pieces in **bold**. 6 | 7 | *** 8 | 9 | On **page xx** [Summary of error]: 10 | 11 | Details of error here. Highlight key pieces in **bold**. 12 | 13 | *** --------------------------------------------------------------------------------