├── 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 |
--------------------------------------------------------------------------------
/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 | 
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 |
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' */
--------------------------------------------------------------------------------