├── launcher ├── __init__.py ├── app.kv └── app.py ├── .gitignore ├── requirements.txt ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── main.yaml ├── data ├── Roboto-Medium.ttf └── kivylauncher.ttf ├── art └── fontello │ ├── font │ ├── kivylauncher.eot │ ├── kivylauncher.ttf │ ├── kivylauncher.woff │ ├── kivylauncher.woff2 │ └── kivylauncher.svg │ ├── css │ ├── kivylauncher-codes.css │ ├── kivylauncher-ie7-codes.css │ ├── kivylauncher-ie7.css │ ├── kivylauncher.css │ ├── animation.css │ └── kivylauncher-embedded.css │ ├── LICENSE.txt │ ├── config.json │ ├── README.txt │ └── demo.html ├── LICENSE ├── README.md └── main.py /launcher/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyo 2 | *.pyc 3 | .ropeproject 4 | bin 5 | .buildozer 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | kivy==2.0.0 2 | pyjnius==1.3.0 3 | buildozer==1.2.0 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | open_collective: kivy 3 | -------------------------------------------------------------------------------- /data/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivy/kivy-launcher/HEAD/data/Roboto-Medium.ttf -------------------------------------------------------------------------------- /data/kivylauncher.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivy/kivy-launcher/HEAD/data/kivylauncher.ttf -------------------------------------------------------------------------------- /art/fontello/font/kivylauncher.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivy/kivy-launcher/HEAD/art/fontello/font/kivylauncher.eot -------------------------------------------------------------------------------- /art/fontello/font/kivylauncher.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivy/kivy-launcher/HEAD/art/fontello/font/kivylauncher.ttf -------------------------------------------------------------------------------- /art/fontello/font/kivylauncher.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivy/kivy-launcher/HEAD/art/fontello/font/kivylauncher.woff -------------------------------------------------------------------------------- /art/fontello/font/kivylauncher.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kivy/kivy-launcher/HEAD/art/fontello/font/kivylauncher.woff2 -------------------------------------------------------------------------------- /art/fontello/css/kivylauncher-codes.css: -------------------------------------------------------------------------------- 1 | 2 | .icon-kivy-glyph:before { content: '\4b'; } /* 'K' */ 3 | .icon-play:before { content: '\50'; } /* 'P' */ 4 | .icon-cw:before { content: '\52'; } /* 'R' */ -------------------------------------------------------------------------------- /art/fontello/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font license info 2 | 3 | 4 | ## Font Awesome 5 | 6 | Copyright (C) 2016 by Dave Gandy 7 | 8 | Author: Dave Gandy 9 | License: SIL () 10 | Homepage: http://fortawesome.github.com/Font-Awesome/ 11 | 12 | 13 | -------------------------------------------------------------------------------- /art/fontello/css/kivylauncher-ie7-codes.css: -------------------------------------------------------------------------------- 1 | 2 | .icon-kivy-glyph { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = 'K '); } 3 | .icon-play { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = 'P '); } 4 | .icon-cw { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = 'R '); } -------------------------------------------------------------------------------- /art/fontello/css/kivylauncher-ie7.css: -------------------------------------------------------------------------------- 1 | [class^="icon-"], [class*=" icon-"] { 2 | font-family: 'kivylauncher'; 3 | font-style: normal; 4 | font-weight: normal; 5 | 6 | /* fix buttons height */ 7 | line-height: 1em; 8 | 9 | /* you can be more comfortable with increased icons size */ 10 | /* font-size: 120%; */ 11 | } 12 | 13 | .icon-kivy-glyph { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = 'K '); } 14 | .icon-play { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = 'P '); } 15 | .icon-cw { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = 'R '); } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Code example showing the issue: 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Logs/output** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Platform (please complete the following information):** 23 | - OS: [e.g. windows 10 /OSX 10.12 /linux/android 8/IOS 12…] 24 | - Python version. 25 | - release or git branch/commit 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kivy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | schedule: 8 | # every 1st day of the month at 10:30 9 | - cron: '30 10 1 * *' 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | 18 | # used to cache dependencies with a timeout 19 | - name: Get Date 20 | id: get-date 21 | run: | 22 | echo "::set-output name=date::$(/bin/date -u "+%Y%m%d")" 23 | shell: bash 24 | 25 | - name: Cache Buildozer global directory 26 | uses: actions/cache@v3 27 | with: 28 | path: .buildozer_global 29 | key: buildozer-global-${{ hashFiles('buildozer.spec') }} # Replace with your path 30 | 31 | - uses: actions/cache@v3 32 | with: 33 | path: .buildozer 34 | key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ hashFiles('buildozer.spec') }} 35 | 36 | - name: Build with Buildozer 37 | run: | 38 | pip3 install --user --upgrade buildozer Cython virtualenv 39 | export PATH=$PATH:~/.local/bin/ 40 | export APP_ANDROID_ACCEPT_SDK_LICENSE=1 41 | export BUILDOZER_WARN_ON_ROOT=0 42 | sudo apt update 43 | sudo apt install -y git zip unzip openjdk-17-jdk python3-pip autoconf libtool pkg-config zlib1g-dev libncurses5-dev libncursesw5-dev libtinfo5 cmake libffi-dev libssl-dev 44 | cd ${{ github.workspace }} 45 | buildozer android debug 46 | 47 | - name: Upload artifacts 48 | uses: actions/upload-artifact@v3 49 | with: 50 | name: package 51 | path: bin/*.apk 52 | -------------------------------------------------------------------------------- /art/fontello/font/kivylauncher.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2018 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kivy Launcher 2 | 3 | (work in progress, not yet published on Google Play) 4 | 5 | This is a reboot of the previously pygame/kivy launcher, implemented in Java in Python for android. It was barely maintainable, and with the rewrite of the new Python for android, it was lost. 6 | 7 | This version aimed to provide a replacement for the launcher, but works also on desktop, on Python 2 or 3. 8 | 9 | Anybody can clone the repo, add the dependencies we would not provide by default, and recompile it. 10 | 11 | ![kivy-launcher](https://user-images.githubusercontent.com/37904/37256979-0611d5be-2563-11e8-98a6-485e656b0f4b.png) 12 | 13 | ## How it works 14 | 15 | Follow the guide the same as before: 16 | 17 | https://kivy.org/docs/guide/packaging-android.html#packaging-your-application-for-the-kivy-launcher 18 | 19 | Then just start the launcher, you should see your application listed, then press play. 20 | 21 | ## `android.txt` specification 22 | 23 | - `title`: Title of the application 24 | - `author`: Author of the application 25 | - `orientation`: Default orientation, one of "landscape", "portrait", "sensor" 26 | 27 | ## Works 28 | 29 | - Provide a simple UI to discover and start another app 30 | - Start another main.py as a `__name__ == '__main__'` 31 | - Reduce to the minimum the overhead of the launcher to launch another app 32 | - Support landscape / portrait / sensor 33 | 34 | ## Ideas 35 | 36 | - Act as a server to just launch any Kivy-based app from desktop to mobile 37 | - Ability to configure multiple paths to look for applications 38 | - Different ordering: by name, last updated, size 39 | - Add tiny icon to show what application orientation is 40 | - Allow to change multiple configuration token / environemnt (like different density/dpi to simulate other screens) 41 | - Support for application without "android.txt" 42 | -------------------------------------------------------------------------------- /art/fontello/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kivylauncher", 3 | "css_prefix_text": "icon-", 4 | "css_use_suffix": false, 5 | "hinting": true, 6 | "units_per_em": 1000, 7 | "ascent": 850, 8 | "glyphs": [ 9 | { 10 | "uid": "ce06b5805120d0c2f8d60cd3f1a4fdb5", 11 | "css": "play", 12 | "code": 80, 13 | "src": "fontawesome" 14 | }, 15 | { 16 | "uid": "bc71f4c6e53394d5ba46b063040014f1", 17 | "css": "cw", 18 | "code": 82, 19 | "src": "fontawesome" 20 | }, 21 | { 22 | "uid": "835ce8006fc9e7ae5f5b84be827f2690", 23 | "css": "kivy-glyph", 24 | "code": 75, 25 | "src": "custom_icons", 26 | "selected": true, 27 | "svg": { 28 | "path": "M390.4 0V579.4C390.4 632.3 422.9 711 460.2 748.2L498.3 786.4 507.3 795.4 689.3 977.4C703.9 992 723.7 1000 744.5 1000 765.2 1000 785 992 799.6 977.4L1029.2 749.2C1043.9 734.6 1051.9 715.2 1051.9 694.5 1052.3 673.7 1044.3 653.9 1029.7 639.3L742.6 352.2 733.6 343.2ZM0 0.9V606.8L255.5 351.2C281.5 325.3 281.5 282.9 255.5 256.5ZM1519.7 237.8C1518.1 237.8 1516.3 237.9 1514.4 238.1L810.9 317.8 1135.3 641.7 1522.4 255.1C1532.3 245.2 1530.6 238.2 1519.7 237.8ZM317.8 391.3L62.2 646.9C36.3 673.3 36.3 715.7 62.2 742.1L317.8 997.6ZM1514.4 238.1L810.9 317.8 1135.3 641.7 1522.4 255.1C1533.7 243.8 1529.9 236.2 1514.4 238.1ZM1029.7 639.3L733.6 343.2 498.3 786.4 689.3 977.4C703.9 992 723.7 1000 744.5 1000V1000C765.2 1000 785 992 799.6 977.4L1029.2 749.2C1043.8 734.6 1051.9 715.2 1051.9 694.5 1052.3 673.7 1044.3 653.9 1029.7 639.3ZM390.4 0V579.4C390.4 632.2 422.9 711 460.2 748.2L498.3 786.4 733.6 343.2ZM62.2 742.1L317.8 997.6V391.3L62.2 646.9C36.3 673.3 36.3 715.7 62.2 742.1ZM255.5 256.5L0 0.9V606.8L255.5 351.2C281.5 325.3 281.5 282.9 255.5 256.5Z", 29 | "width": 1529 30 | }, 31 | "search": [ 32 | "kivy-glyph" 33 | ] 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | def run_entrypoint(entrypoint): 5 | import runpy 6 | import sys 7 | import os 8 | entrypoint_path = os.path.dirname(entrypoint) 9 | sys.path.append(os.path.realpath(entrypoint_path)) 10 | runpy.run_path( 11 | entrypoint, 12 | run_name="__main__") 13 | 14 | 15 | def run_launcher(tb=None): 16 | from launcher.app import Launcher 17 | Launcher().run() 18 | 19 | 20 | def dispatch(): 21 | import os 22 | 23 | # desktop launch 24 | print("dispathc!") 25 | entrypoint = os.environ.get("KIVYLAUNCHER_ENTRYPOINT") 26 | if entrypoint is not None: 27 | return run_entrypoint(entrypoint) 28 | 29 | # try android 30 | try: 31 | from jnius import autoclass 32 | activity = autoclass("org.kivy.android.PythonActivity").mActivity 33 | intent = activity.getIntent() 34 | entrypoint = intent.getStringExtra("entrypoint") 35 | orientation = intent.getStringExtra("orientation") 36 | 37 | if orientation == "portrait": 38 | # SCREEN_ORIENTATION_PORTRAIT 39 | activity.setRequestedOrientation(0x1) 40 | elif orientation == "landscape": 41 | # SCREEN_ORIENTATION_LANDSCAPE 42 | activity.setRequestedOrientation(0x0) 43 | elif orientation == "sensor": 44 | # SCREEN_ORIENTATION_SENSOR 45 | activity.setRequestedOrientation(0x4) 46 | 47 | if entrypoint is not None: 48 | try: 49 | return run_entrypoint(entrypoint) 50 | except Exception: 51 | import traceback 52 | traceback.print_exc() 53 | return 54 | except Exception: 55 | import traceback 56 | traceback.print_exc() 57 | 58 | run_launcher() 59 | 60 | 61 | if __name__ == "__main__": 62 | dispatch() 63 | -------------------------------------------------------------------------------- /art/fontello/css/kivylauncher.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'kivylauncher'; 3 | src: url('../font/kivylauncher.eot?27876560'); 4 | src: url('../font/kivylauncher.eot?27876560#iefix') format('embedded-opentype'), 5 | url('../font/kivylauncher.woff2?27876560') format('woff2'), 6 | url('../font/kivylauncher.woff?27876560') format('woff'), 7 | url('../font/kivylauncher.ttf?27876560') format('truetype'), 8 | url('../font/kivylauncher.svg?27876560#kivylauncher') format('svg'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ 13 | /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ 14 | /* 15 | @media screen and (-webkit-min-device-pixel-ratio:0) { 16 | @font-face { 17 | font-family: 'kivylauncher'; 18 | src: url('../font/kivylauncher.svg?27876560#kivylauncher') format('svg'); 19 | } 20 | } 21 | */ 22 | 23 | [class^="icon-"]:before, [class*=" icon-"]:before { 24 | font-family: "kivylauncher"; 25 | font-style: normal; 26 | font-weight: normal; 27 | speak: none; 28 | 29 | display: inline-block; 30 | text-decoration: inherit; 31 | width: 1em; 32 | margin-right: .2em; 33 | text-align: center; 34 | /* opacity: .8; */ 35 | 36 | /* For safety - reset parent styles, that can break glyph codes*/ 37 | font-variant: normal; 38 | text-transform: none; 39 | 40 | /* fix buttons height, for twitter bootstrap */ 41 | line-height: 1em; 42 | 43 | /* Animation center compensation - margins should be symmetric */ 44 | /* remove if not needed */ 45 | margin-left: .2em; 46 | 47 | /* you can be more comfortable with increased icons size */ 48 | /* font-size: 120%; */ 49 | 50 | /* Font smoothing. That was taken from TWBS */ 51 | -webkit-font-smoothing: antialiased; 52 | -moz-osx-font-smoothing: grayscale; 53 | 54 | /* Uncomment for 3D effect */ 55 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ 56 | } 57 | 58 | .icon-kivy-glyph:before { content: '\4b'; } /* 'K' */ 59 | .icon-play:before { content: '\50'; } /* 'P' */ 60 | .icon-cw:before { content: '\52'; } /* 'R' */ -------------------------------------------------------------------------------- /art/fontello/css/animation.css: -------------------------------------------------------------------------------- 1 | /* 2 | Animation example, for spinners 3 | */ 4 | .animate-spin { 5 | -moz-animation: spin 2s infinite linear; 6 | -o-animation: spin 2s infinite linear; 7 | -webkit-animation: spin 2s infinite linear; 8 | animation: spin 2s infinite linear; 9 | display: inline-block; 10 | } 11 | @-moz-keyframes spin { 12 | 0% { 13 | -moz-transform: rotate(0deg); 14 | -o-transform: rotate(0deg); 15 | -webkit-transform: rotate(0deg); 16 | transform: rotate(0deg); 17 | } 18 | 19 | 100% { 20 | -moz-transform: rotate(359deg); 21 | -o-transform: rotate(359deg); 22 | -webkit-transform: rotate(359deg); 23 | transform: rotate(359deg); 24 | } 25 | } 26 | @-webkit-keyframes spin { 27 | 0% { 28 | -moz-transform: rotate(0deg); 29 | -o-transform: rotate(0deg); 30 | -webkit-transform: rotate(0deg); 31 | transform: rotate(0deg); 32 | } 33 | 34 | 100% { 35 | -moz-transform: rotate(359deg); 36 | -o-transform: rotate(359deg); 37 | -webkit-transform: rotate(359deg); 38 | transform: rotate(359deg); 39 | } 40 | } 41 | @-o-keyframes spin { 42 | 0% { 43 | -moz-transform: rotate(0deg); 44 | -o-transform: rotate(0deg); 45 | -webkit-transform: rotate(0deg); 46 | transform: rotate(0deg); 47 | } 48 | 49 | 100% { 50 | -moz-transform: rotate(359deg); 51 | -o-transform: rotate(359deg); 52 | -webkit-transform: rotate(359deg); 53 | transform: rotate(359deg); 54 | } 55 | } 56 | @-ms-keyframes spin { 57 | 0% { 58 | -moz-transform: rotate(0deg); 59 | -o-transform: rotate(0deg); 60 | -webkit-transform: rotate(0deg); 61 | transform: rotate(0deg); 62 | } 63 | 64 | 100% { 65 | -moz-transform: rotate(359deg); 66 | -o-transform: rotate(359deg); 67 | -webkit-transform: rotate(359deg); 68 | transform: rotate(359deg); 69 | } 70 | } 71 | @keyframes spin { 72 | 0% { 73 | -moz-transform: rotate(0deg); 74 | -o-transform: rotate(0deg); 75 | -webkit-transform: rotate(0deg); 76 | transform: rotate(0deg); 77 | } 78 | 79 | 100% { 80 | -moz-transform: rotate(359deg); 81 | -o-transform: rotate(359deg); 82 | -webkit-transform: rotate(359deg); 83 | transform: rotate(359deg); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /art/fontello/README.txt: -------------------------------------------------------------------------------- 1 | This webfont is generated by http://fontello.com open source project. 2 | 3 | 4 | ================================================================================ 5 | Please, note, that you should obey original font licenses, used to make this 6 | webfont pack. Details available in LICENSE.txt file. 7 | 8 | - Usually, it's enough to publish content of LICENSE.txt file somewhere on your 9 | site in "About" section. 10 | 11 | - If your project is open-source, usually, it will be ok to make LICENSE.txt 12 | file publicly available in your repository. 13 | 14 | - Fonts, used in Fontello, don't require a clickable link on your site. 15 | But any kind of additional authors crediting is welcome. 16 | ================================================================================ 17 | 18 | 19 | Comments on archive content 20 | --------------------------- 21 | 22 | - /font/* - fonts in different formats 23 | 24 | - /css/* - different kinds of css, for all situations. Should be ok with 25 | twitter bootstrap. Also, you can skip style and assign icon classes 26 | directly to text elements, if you don't mind about IE7. 27 | 28 | - demo.html - demo file, to show your webfont content 29 | 30 | - LICENSE.txt - license info about source fonts, used to build your one. 31 | 32 | - config.json - keeps your settings. You can import it back into fontello 33 | anytime, to continue your work 34 | 35 | 36 | Why so many CSS files ? 37 | ----------------------- 38 | 39 | Because we like to fit all your needs :) 40 | 41 | - basic file, .css - is usually enough, it contains @font-face 42 | and character code definitions 43 | 44 | - *-ie7.css - if you need IE7 support, but still don't wish to put char codes 45 | directly into html 46 | 47 | - *-codes.css and *-ie7-codes.css - if you like to use your own @font-face 48 | rules, but still wish to benefit from css generation. That can be very 49 | convenient for automated asset build systems. When you need to update font - 50 | no need to manually edit files, just override old version with archive 51 | content. See fontello source code for examples. 52 | 53 | - *-embedded.css - basic css file, but with embedded WOFF font, to avoid 54 | CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain. 55 | We strongly recommend to resolve this issue by `Access-Control-Allow-Origin` 56 | server headers. But if you ok with dirty hack - this file is for you. Note, 57 | that data url moved to separate @font-face to avoid problems with : 8 | font_name: "data/kivylauncher.ttf" 9 | 10 | 11 | size_hint_x: None 12 | width: self.height 13 | canvas.before: 14 | Color: 15 | rgba: rgba("#ffffff66") if self.state == "down" else rgba("#00000000") 16 | Rectangle: 17 | pos: self.pos 18 | size: self.size 19 | 20 | : 21 | text_size: self.width, None 22 | 23 | : 24 | rows: 1 25 | padding: dp(4) 26 | size_hint_y: None 27 | height: dp(48) 28 | spacing: dp(10) 29 | canvas.before: 30 | Color: 31 | rgba: rgba("#3F51B5") 32 | Rectangle: 33 | pos: self.pos 34 | size: self.size 35 | 36 | IconLabel: 37 | text: ICON_KIVY 38 | size_hint_x: None 39 | width: self.height 40 | Label: 41 | text: "Kivy Launcher" 42 | size_hint_x: None 43 | width: self.texture_size[0] 44 | font_size: dp(16) 45 | font_name: "data/Roboto-Medium.ttf" 46 | 47 | IconButton: 48 | text: ICON_REFRESH 49 | on_press: 50 | app.refresh_entries() 51 | 52 | ToggleButton: 53 | text: 'Show logs' if self.state == 'normal' else 'Hide logs' 54 | state: 'down' if app.display_logs else 'normal' 55 | on_state: 56 | app.display_logs = self.state == 'down' 57 | 58 | 59 | : 60 | data_title: "" 61 | data_orientation: "" 62 | data_logo: "data/logo/kivy-icon-64.png" 63 | data_orientation: "" 64 | data_author: "" 65 | data_entry: None 66 | padding: dp(4) 67 | spacing: dp(8) 68 | canvas.before: 69 | Color: 70 | rgba: rgba("#eeeef0") 71 | Rectangle: 72 | pos: self.x + self.height + self.padding[0], self.y - self.padding[1] / 2. 73 | size: self.width, dp(1) 74 | 75 | Image: 76 | source: root.data_logo 77 | size_hint_x: None 78 | width: self.height 79 | BoxLayout: 80 | orientation: "vertical" 81 | padding: 0, dp(4) 82 | LLabel: 83 | text: root.data_title 84 | color: rgba("#454547") 85 | font_name: "data/Roboto-Medium.ttf" 86 | font_size: dp(13) 87 | LLabel: 88 | text: root.data_author 89 | color: rgba("#b4b6b7") 90 | font_size: dp(11) 91 | IconButton: 92 | text: ICON_PLAY 93 | on_release: app.start_activity(root.data_entry) 94 | color: rgba("#b4b6b8") 95 | 96 | 97 | GridLayout: 98 | cols: 1 99 | canvas.before: 100 | Color: 101 | rgba: rgba("#fafafc") 102 | Rectangle: 103 | size: self.size 104 | TopBar 105 | FloatLayout: 106 | RecycleView: 107 | id: rv 108 | pos_hint: {'pos': (0, 0)} 109 | viewclass: "LauncherEntry" 110 | RecycleBoxLayout: 111 | size_hint_y: None 112 | height: self.minimum_height 113 | orientation: "vertical" 114 | spacing: dp(2) 115 | default_size: None, dp(48) 116 | default_size_hint: 1, None 117 | 118 | RecycleView: 119 | viewclass: 'LogLabel' 120 | data: [{'text': log} for log in app.logs] 121 | _top: 0 122 | pos_hint: {'top': self._top, 'x': 0} 123 | visible: app.display_logs 124 | on_visible: 125 | A.cancel_all(self, '_top') 126 | A(_top=1 if self.visible else 0, d=.3, t='out_quad').start(self) 127 | 128 | canvas.before: 129 | Color: 130 | rgba: rgba("#CCCCCCCC") 131 | Rectangle: 132 | pos: self.pos 133 | size: self.size 134 | 135 | RecycleBoxLayout: 136 | orientation: 'vertical' 137 | size_hint_y: None 138 | height: self.minimum_height 139 | default_size_hint: None, None 140 | default_size: 0, 20 141 | padding: 5, 5 142 | 143 | Label: 144 | text: 145 | ''' 146 | Please install applications in one of the following directories 147 | - {} 148 | '''.format('\n -'.join(app.paths)) 149 | pos_hint: {'pos': (0, 0)} 150 | color: rgba("#222222" if not rv.data else "#00000000") 151 | 152 | : 153 | color: rgba("#222222FF") 154 | pos_hint: {'x': 0} 155 | width: self.texture_size[0] 156 | -------------------------------------------------------------------------------- /launcher/app.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | from datetime import datetime 5 | from kivy.lang import Builder 6 | from kivy.app import App 7 | from kivy.utils import platform 8 | from kivy.properties import ListProperty, BooleanProperty 9 | from glob import glob 10 | from os.path import dirname, join, exists 11 | import traceback 12 | 13 | KIVYLAUNCHER_PATHS = os.environ.get("KIVYLAUNCHER_PATHS") 14 | 15 | 16 | class Launcher(App): 17 | paths = ListProperty() 18 | logs = ListProperty() 19 | display_logs = BooleanProperty(False) 20 | 21 | def log(self, log): 22 | print(log) 23 | self.logs.append(f"{datetime.now().strftime('%X.%f')}: {log}") 24 | 25 | def build(self): 26 | self.log('start of log') 27 | 28 | if KIVYLAUNCHER_PATHS: 29 | self.paths.extend(KIVYLAUNCHER_PATHS.split(",")) 30 | 31 | if platform == 'android': 32 | from jnius import autoclass 33 | Environment = autoclass('android.os.Environment') 34 | sdcard_path = Environment.getExternalStorageDirectory()\ 35 | .getAbsolutePath() 36 | self.paths = [sdcard_path + "/kivy"] 37 | else: 38 | self.paths = [os.path.expanduser("~/kivy")] 39 | 40 | self.root = Builder.load_file("launcher/app.kv") 41 | self.refresh_entries() 42 | 43 | if platform == 'android': 44 | from android.permissions import request_permissions, Permission 45 | request_permissions([Permission.READ_EXTERNAL_STORAGE]) 46 | 47 | def refresh_entries(self): 48 | data = [] 49 | self.log('starting refresh') 50 | for entry in self.find_entries(paths=self.paths): 51 | self.log(f'found entry {entry}') 52 | data.append({ 53 | "data_title": entry.get("title", "- no title -"), 54 | "data_path": entry.get("path"), 55 | "data_logo": entry.get("logo", "data/logo/kivy-icon-64.png"), 56 | "data_orientation": entry.get("orientation", ""), 57 | "data_author": entry.get("author", ""), 58 | "data_entry": entry 59 | }) 60 | self.root.ids.rv.data = data 61 | 62 | def find_entries(self, path=None, paths=None): 63 | self.log(f'looking for entries in {paths} or {path}') 64 | if paths is not None: 65 | for path in paths: 66 | for entry in self.find_entries(path=path): 67 | yield entry 68 | 69 | elif path is not None: 70 | if not exists(path): 71 | self.log(f'{path} does not exist') 72 | return 73 | 74 | self.log('{os.listdir(path)}') 75 | for filename in glob("{}/*/android.txt".format(path)): 76 | self.log(f'{filename} exist') 77 | entry = self.read_entry(filename) 78 | if entry: 79 | yield entry 80 | 81 | def read_entry(self, filename): 82 | self.log(f'reading entry {filename}') 83 | data = {} 84 | try: 85 | with open(filename, "r") as fd: 86 | lines = fd.readlines() 87 | for line in lines: 88 | k, v = line.strip().split("=", 1) 89 | data[k] = v 90 | except Exception: 91 | traceback.print_exc() 92 | return None 93 | data["entrypoint"] = join(dirname(filename), "main.py") 94 | data["path"] = dirname(filename) 95 | icon = join(data["path"], "icon.png") 96 | if exists(icon): 97 | data["icon"] = icon 98 | return data 99 | 100 | def start_activity(self, entry): 101 | if platform == "android": 102 | self.start_android_activity(entry) 103 | else: 104 | self.start_desktop_activity(entry) 105 | 106 | def start_desktop_activity(self, entry): 107 | import sys 108 | from subprocess import Popen 109 | entrypoint = entry["entrypoint"] 110 | env = os.environ.copy() 111 | env["KIVYLAUNCHER_ENTRYPOINT"] = entrypoint 112 | main_py = os.path.realpath(os.path.join( 113 | os.path.dirname(__file__), "..", "main.py")) 114 | cmd = Popen([sys.executable, main_py], env=env) 115 | cmd.communicate() 116 | 117 | def start_android_activity(self, entry): 118 | self.log('starting activity') 119 | from jnius import autoclass 120 | PythonActivity = autoclass("org.kivy.android.PythonActivity") 121 | System = autoclass("java.lang.System") 122 | activity = PythonActivity.mActivity 123 | Intent = autoclass("android.content.Intent") 124 | String = autoclass("java.lang.String") 125 | 126 | j_entrypoint = String(entry.get("entrypoint")) 127 | j_orientation = String(entry.get("orientation")) 128 | 129 | self.log('creating intent') 130 | intent = Intent( 131 | activity.getApplicationContext(), 132 | PythonActivity 133 | ) 134 | intent.putExtra("entrypoint", j_entrypoint) 135 | intent.putExtra("orientation", j_orientation) 136 | self.log(f'ready to start intent {j_entrypoint} {j_orientation}') 137 | activity.startActivity(intent) 138 | self.log('activity started') 139 | System.exit(0) 140 | -------------------------------------------------------------------------------- /art/fontello/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 278 | 279 | 291 | 292 | 293 |
294 |

kivylauncher font demo

295 | 298 |
299 |
300 |
301 |
K icon-kivy-glyph0x4b
302 |
P icon-play0x50
303 |
R icon-cw0x52
304 |
305 |
306 | 307 | 308 | -------------------------------------------------------------------------------- /art/fontello/css/kivylauncher-embedded.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'kivylauncher'; 3 | src: url('../font/kivylauncher.eot?73377830'); 4 | src: url('../font/kivylauncher.eot?73377830#iefix') format('embedded-opentype'), 5 | url('../font/kivylauncher.svg?73377830#kivylauncher') format('svg'); 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | @font-face { 10 | font-family: 'kivylauncher'; 11 | src: url('data:application/octet-stream;base64,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') format('woff'), 12 | url('data:application/octet-stream;base64,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') format('truetype'); 13 | } 14 | /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ 15 | /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ 16 | /* 17 | @media screen and (-webkit-min-device-pixel-ratio:0) { 18 | @font-face { 19 | font-family: 'kivylauncher'; 20 | src: url('../font/kivylauncher.svg?73377830#kivylauncher') format('svg'); 21 | } 22 | } 23 | */ 24 | 25 | [class^="icon-"]:before, [class*=" icon-"]:before { 26 | font-family: "kivylauncher"; 27 | font-style: normal; 28 | font-weight: normal; 29 | speak: none; 30 | 31 | display: inline-block; 32 | text-decoration: inherit; 33 | width: 1em; 34 | margin-right: .2em; 35 | text-align: center; 36 | /* opacity: .8; */ 37 | 38 | /* For safety - reset parent styles, that can break glyph codes*/ 39 | font-variant: normal; 40 | text-transform: none; 41 | 42 | /* fix buttons height, for twitter bootstrap */ 43 | line-height: 1em; 44 | 45 | /* Animation center compensation - margins should be symmetric */ 46 | /* remove if not needed */ 47 | margin-left: .2em; 48 | 49 | /* you can be more comfortable with increased icons size */ 50 | /* font-size: 120%; */ 51 | 52 | /* Uncomment for 3D effect */ 53 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ 54 | } 55 | .icon-kivy-glyph:before { content: '\4b'; } /* 'K' */ 56 | .icon-play:before { content: '\50'; } /* 'P' */ 57 | .icon-cw:before { content: '\52'; } /* 'R' */ --------------------------------------------------------------------------------