Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ logs/*
config.json
wallpaper.txt
port.txt
ui_port.txt
ui_port.txt
bin
.buildozer
test*
File renamed without changes
3 changes: 2 additions & 1 deletion app_src/hot_reload.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# DEBUG=1 python3 hot_reload.py
import os
from kaki.app import App
from kivy.factory import Factory
Expand Down Expand Up @@ -74,7 +75,7 @@ class MDLive(App,MDApp):

def build_app(self, *args):
# return Factory.MyPopUp()
return Factory.GalleryScreen()
return Factory.FullscreenScreen()

def on_start(self):
# self.theme_cls.theme_style = "Light"
Expand Down
264 changes: 158 additions & 106 deletions app_src/ui/screens/full_screen.py

Large diffs are not rendered by default.

13 changes: 10 additions & 3 deletions app_src/ui/screens/gallery_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.metrics import dp, sp
from kivy.properties import StringProperty, NumericProperty, ListProperty, BooleanProperty, ObjectProperty
from kivy.properties import StringProperty, NumericProperty, ListProperty, BooleanProperty, ObjectProperty, DictProperty
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.button import Button
from kivy.uix.image import AsyncImage
Expand Down Expand Up @@ -298,6 +298,7 @@ def change_preview_img_size(self,widget,number_of_cols):
class GalleryScreen(MyMDScreen):
current_tab = StringProperty(GalleryTabs.BOTH.value)
wallpapers = ListProperty([])
images_data = DictProperty({})

def __init__(self, **kwargs):

Expand Down Expand Up @@ -347,6 +348,11 @@ def run_widgets_creation( *args):
self.generate_tab_widgets(tab_name=GalleryTabs.NOON.value, wallpapers=self._filter_existing_paths(my_config.get_noon_wallpapers()))
self.current_tab = GalleryTabs.BOTH.value
self.on_current_tab(None, self.current_tab)
self.images_data={ #for full_screen init
GalleryTabs.BOTH.value: self.tab_instances[GalleryTabs.BOTH.value]["wallpapers"],
GalleryTabs.DAY.value: self.tab_instances[GalleryTabs.DAY.value]["wallpapers"],
GalleryTabs.NOON.value: self.tab_instances[GalleryTabs.NOON.value]["wallpapers"],
}

if no_clock: # using clock in init breaks DateGroupLayout height
run_widgets_creation()
Expand Down Expand Up @@ -409,11 +415,12 @@ def show_chooser(dt=None):
# print("error_testing_picker", error_testing_picker)

def generate_tab_widgets(self, tab_name, wallpapers, dt=None):
self.wallpapers = wallpapers
# self.wallpapers = wallpapers
tab_title = f"{len(self.wallpapers)} images found"

self.wallpapers = sorted(
self.wallpapers,
wallpapers,
# self.wallpapers,
key=lambda image_path: os.stat(image_path).st_mtime,
reverse=True # newest first
)
Expand Down
72 changes: 64 additions & 8 deletions app_src/ui/screens/logs_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ def __init__(self, **kwargs):

# Buttons at bottom
buttons = BoxLayout(size_hint_y=None, height=dp(50), spacing=dp(10))
add_btn = Button(text="Add Test Log")
add_btn.bind(on_release=lambda *_: self.add_test_log())
add_btn = Button(text="Export Logs")
add_btn.bind(on_release=lambda *_: self.export_logs())
clear_btn = Button(text="Clear Logs")
clear_btn.bind(on_release=lambda *_: self.clear_logs())
buttons.add_widget(add_btn)
Expand Down Expand Up @@ -158,12 +158,68 @@ def add_log(self, message):
f.write(full_log+"\n")
self.scroll.scroll_y = 0

def add_test_log(self):
self.add_log("INFO This is a normal log message")
self.add_log("WARN Something looks suspicious")
self.add_log("ERROR Something broke badly")
self.add_log("EXCEPTION ValueError: invalid input")
self.add_log("TRACEBACK File \"main.py\", line 42")
def export_logs(self, *_):
if not os.path.exists(self.log_file_path):
toast("No logs to export")
return

from jnius import autoclass
from android_notify.config import get_python_activity_context

context = get_python_activity_context()

Environment = autoclass('android.os.Environment')
ContentValues = autoclass('android.content.ContentValues')
BuildVersion = autoclass('android.os.Build$VERSION')
File = autoclass('java.io.File')
FileInputStream = autoclass('java.io.FileInputStream')

if BuildVersion.SDK_INT >= 29:
MediaStoreDownloads = autoclass('android.provider.MediaStore$Downloads')
MediaColumns = autoclass('android.provider.MediaStore$MediaColumns')

content_values = ContentValues()
content_values.put(MediaColumns.DISPLAY_NAME, "app_logs.txt")
content_values.put(MediaColumns.MIME_TYPE, "text/plain")
content_values.put(MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)

resolver = context.getContentResolver()
uri = resolver.insert(MediaStoreDownloads.EXTERNAL_CONTENT_URI, content_values)

if uri:
try:
input_stream = FileInputStream(File(self.log_file_path))
output_stream = resolver.openOutputStream(uri)

buffer = bytearray(8192)
while True:
length = input_stream.read(buffer)
if length <= 0:
break
output_stream.write(buffer, 0, length)

input_stream.close()
output_stream.close()
toast("Logs exported to Downloads")
except Exception as e:
print("Export error:", e)
toast("Export failed")
else:
toast("Export failed")
else:
downloads_dir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS
).getAbsolutePath()
dest_path = os.path.join(downloads_dir, "app_logs.txt")
try:
with open(self.log_file_path, "r") as src, open(dest_path, "w") as dst:
dst.write(src.read())
MediaScannerConnection = autoclass('android.media.MediaScannerConnection')
MediaScannerConnection.scanFile(context, [dest_path], ["text/plain"], None)
toast("Logs exported to Downloads")
except Exception as e:
print("Export error:", e)
toast("Export failed")

def clear_logs(self):
self.logs_layout.clear_widgets()
Expand Down
14 changes: 9 additions & 5 deletions app_src/ui/screens/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@ def __init__(self, **kwargs):
self.app = get_app()
self.welcome_screen = WelcomeScreen()
self.gallery_screen = GalleryScreen()
self.full_screen = FullscreenScreen()
self.full_screen = FullscreenScreen(images_data=self.gallery_screen.images_data)
self.settings_screen = SettingsScreen()
self.settings_screen = SettingsScreen()
self.log_screen = LogsScreen()
self.download_apk_screen = DownloadApkScreen()
# self.download_apk_screen = DownloadApkScreen()

self.add_widget(self.gallery_screen)
self.add_widget(self.full_screen)
self.add_widget(self.settings_screen)
self.add_widget(self.welcome_screen)
self.add_widget(self.log_screen)
self.add_widget(self.download_apk_screen)
# self.add_widget(self.download_apk_screen)
self.__register_rotate_listener()
# self.__run_rotate_method_for_each_screen("BOTTOM")

Expand Down Expand Up @@ -85,8 +86,11 @@ def go_to_thumbs(self, _=None):
def open_image_in_full_screen(self, index):
self.transition = NoTransition()
self.current = "fullscreen"
self.full_screen.update_images(index)
self.full_screen.carousel.index = index
self.full_screen.current_tab = self.gallery_screen.current_tab
self.full_screen.index = index

# self.full_screen.update_images(index)
# self.full_screen.carousel.index = index

def on_rotation(self, rotation):
rotation=self.__get_rotation_name(rotation)
Expand Down
2 changes: 1 addition & 1 deletion app_src/utils/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def makeFolder(my_folder):
return my_folder


def appFolder() -> str | bytes:
def appFolder() -> str:
"""Creates (if needed) and returns the Laner download folder path."""

if on_android_platform():
Expand Down
5 changes: 3 additions & 2 deletions buildozer.spec
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@ android.permissions = RECEIVE_BOOT_COMPLETED, INTERNET, VIBRATE, USE_EXACT_ALARM
#android.permissions = RECEIVE_BOOT_COMPLETED, INTERNET, VIBRATE, USE_EXACT_ALARM, SCHEDULE_EXACT_ALARM, FOREGROUND_SERVICE, FOREGROUND_SERVICE_DATA_SYNC, POST_NOTIFICATIONS, SET_WALLPAPER, READ_MEDIA_IMAGES, (name=android.permission.READ_EXTERNAL_STORAGE;maxSdkVersion=32), (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=28)
android.add_src = %(source.dir)s/android/src
android.add_resources = %(source.dir)s/android/res
android.gradle_dependencies = androidx.core:core-ktx:1.12.0, com.google.android.material:material:1.12.0
android.gradle_dependencies = com.google.android.material:material:1.12.0
#android.gradle_dependencies = com.google.android.material:material:1.6.0, androidx.core:core-ktx:1.15.0, androidx.core:core:1.6.0, androidx.work:work-runtime:2.9.0
android.enable_androidx = True
p4a.hook = %(source.dir)s/android/p4a/hook.py




android.api = 35
android.api = 36
android.ndk = 29
p4a.branch = develop


Expand Down
6 changes: 6 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kivy
android-notify
android-widgets
python-osc
https://github.com/Fector101/plyer/archive/feature/file-type-parser.zip
https://github.com/kivymd/KivyMD/archive/master.zip