[WIP] Android updates to allow library folder selection.

This commit is contained in:
Luke Hubmayer-Werner 2024-11-03 23:40:35 +09:00 committed by Luke Hubmayer-Werner
parent e1c12fe813
commit 093d620bfe
17 changed files with 317 additions and 43 deletions

View File

@ -8,21 +8,20 @@ export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../../Rhythm.x86_64"
patch_list=PoolStringArray( )
script_export_mode=1
script_encryption_key=""
[preset.0.options]
custom_template/debug=""
custom_template/release=""
binary_format/architecture="x86_64"
binary_format/embed_pck=false
texture_format/bptc=false
texture_format/s3tc=true
texture_format/etc=false
texture_format/etc2=false
texture_format/no_bptc_fallbacks=true
binary_format/64_bits=true
binary_format/embed_pck=false
custom_template/release=""
custom_template/debug=""
[preset.1]
@ -34,50 +33,55 @@ export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../../Rhythm.apk"
patch_list=PoolStringArray( )
script_export_mode=1
script_encryption_key=""
[preset.1.options]
graphics/32_bits_framebuffer=true
xr_features/xr_mode=0
xr_features/degrees_of_freedom=0
xr_features/hand_tracking=0
one_click_deploy/clear_previous_install=false
custom_template/debug=""
custom_template/release=""
custom_template/use_custom_build=false
command_line/extra_args=""
version/code=1
version/name="1.0"
package/unique_name="au.ufeff.rhythmgame"
package/name="Rhythm Game"
package/signed=true
screen/immersive_mode=true
screen/orientation=0
screen/support_small=true
screen/support_normal=true
screen/support_large=true
screen/support_xlarge=true
screen/opengl_debug=false
launcher_icons/main_192x192=""
launcher_icons/adaptive_foreground_432x432=""
launcher_icons/adaptive_background_432x432=""
custom_build/use_custom_build=false
custom_build/export_format=0
custom_build/min_sdk=""
custom_build/target_sdk=""
architectures/armeabi-v7a=true
architectures/arm64-v8a=true
architectures/x86=false
architectures/x86_64=false
keystore/debug=""
keystore/debug_user=""
keystore/debug_password=""
keystore/release=""
keystore/release_user=""
keystore/release_password=""
one_click_deploy/clear_previous_install=false
version/code=1
version/name="1.0"
package/unique_name="au.ufeff.rhythmgame"
package/name="Rhythm Game"
package/signed=true
package/classify_as_game=true
package/retain_data_on_uninstall=false
package/exclude_from_recents=false
launcher_icons/main_192x192=""
launcher_icons/adaptive_foreground_432x432=""
launcher_icons/adaptive_background_432x432=""
graphics/opengl_debug=false
xr_features/xr_mode=0
xr_features/hand_tracking=0
xr_features/hand_tracking_frequency=0
xr_features/passthrough=0
screen/immersive_mode=true
screen/support_small=true
screen/support_normal=true
screen/support_large=true
screen/support_xlarge=true
user_data_backup/allow=false
command_line/extra_args=""
apk_expansion/enable=false
apk_expansion/SALT=""
apk_expansion/public_key=""
architectures/armeabi-v7a=true
architectures/arm64-v8a=true
architectures/x86=false
architectures/x86_64=false
permissions/custom_permissions=PoolStringArray( )
permissions/custom_permissions=PoolStringArray( "MANAGE_EXTERNAL_STORAGE" )
permissions/access_checkin_properties=false
permissions/access_coarse_location=false
permissions/access_fine_location=false
@ -150,6 +154,7 @@ permissions/location_hardware=false
permissions/manage_accounts=false
permissions/manage_app_tokens=false
permissions/manage_documents=false
permissions/manage_external_storage=true
permissions/master_clear=false
permissions/media_content_control=false
permissions/modify_audio_settings=false
@ -158,6 +163,7 @@ permissions/mount_format_filesystems=false
permissions/mount_unmount_filesystems=false
permissions/nfc=false
permissions/persistent_activity=false
permissions/post_notifications=false
permissions/process_outgoing_calls=false
permissions/read_calendar=false
permissions/read_call_log=false
@ -234,15 +240,27 @@ export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
patch_list=PoolStringArray( )
script_export_mode=1
script_encryption_key=""
[preset.2.options]
custom_template/debug=""
custom_template/release=""
variant/export_type=0
vram_texture_compression/for_desktop=true
vram_texture_compression/for_mobile=false
html/export_icon=true
html/custom_html_shell=""
html/head_include=""
custom_template/release=""
custom_template/debug=""
html/canvas_resize_policy=2
html/focus_canvas_on_start=true
html/experimental_virtual_keyboard=false
progressive_web_app/enabled=false
progressive_web_app/offline_page=""
progressive_web_app/display=1
progressive_web_app/orientation=0
progressive_web_app/icon_144x144=""
progressive_web_app/icon_180x180=""
progressive_web_app/icon_512x512=""
progressive_web_app/background_color=Color( 0, 0, 0, 1 )

23
main.gd
View File

@ -1,21 +1,40 @@
extends Control
onready var mainMenu := $'%mainMenu'
onready var optionPanel := $'%OptionPanel'
const touchGamePath := 'res://scenes/RadialGame.tscn'
const stepGamePath := 'res://scenes/StepGame.tscn'
var touchGameScene := preload(touchGamePath)
var stepGameScene := preload(stepGamePath)
const touchGameScene := preload(touchGamePath)
const stepGameScene := preload(stepGamePath)
const SettingsMenu := preload('res://scenes/SettingsMenu.tscn')
var activeGame: Node = null
func exit_mode() -> void:
remove_child(activeGame)
activeGame = null
mainMenu.show()
optionPanel.show()
func _on_MainMenu_start_stepgame() -> void:
mainMenu.hide()
activeGame = stepGameScene.instance()
activeGame.connect('exit_mode', self, 'exit_mode')
add_child_below_node(mainMenu, activeGame)
func _on_MainMenu_start_touchgame() -> void:
mainMenu.hide()
activeGame = touchGameScene.instance()
activeGame.connect('exit_mode', self, 'exit_mode')
add_child_below_node(mainMenu, activeGame)
activeGame.alignment_horizontal = AspectRatioContainer.ALIGN_BEGIN
func _on_mainMenu_open_settings():
mainMenu.hide()
optionPanel.hide()
activeGame = SettingsMenu.instance()
activeGame.connect('exit_mode', self, 'exit_mode')
add_child_below_node(mainMenu, activeGame)

View File

@ -19,6 +19,7 @@ __meta__ = {
unique_name_in_owner = true
[node name="OptionPanel" parent="." instance=ExtResource( 13 )]
unique_name_in_owner = true
anchor_left = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
@ -36,5 +37,6 @@ __meta__ = {
"_edit_use_anchors_": false
}
[connection signal="open_settings" from="mainMenu" to="." method="_on_mainMenu_open_settings"]
[connection signal="start_stepgame" from="mainMenu" to="." method="_on_MainMenu_start_stepgame"]
[connection signal="start_touchgame" from="mainMenu" to="." method="_on_MainMenu_start_touchgame"]

View File

@ -39,7 +39,6 @@ gdscript/warnings/unused_variable=false
gdscript/warnings/shadowed_variable=false
gdscript/warnings/unused_argument=false
gdscript/warnings/unused_signal=false
gdscript/warnings/return_value_discarded=false
gdscript/warnings/integer_division=false
[display]

View File

@ -0,0 +1,52 @@
extends HBoxContainer
onready var le_directory := $le_directory
onready var btn_browse := $btn_browse
onready var btn_remove := $btn_remove
signal path_updated
export var directory: String = "" setget set_directory, get_directory
func set_directory(value: String):
directory = value
if le_directory:
le_directory.text = directory
emit_signal('path_updated', value)
func get_directory():
return le_directory.text
export var removable: bool = true setget set_removable
func set_removable(value: bool):
removable = value
if btn_remove:
btn_remove.disabled = not removable
export var readonly: bool = false setget set_readonly
func set_readonly(value: bool):
readonly = value
if le_directory:
le_directory.editable = not readonly
if btn_browse:
btn_browse.disabled = readonly
func _ready():
le_directory.text = directory
le_directory.editable = not readonly
btn_browse.disabled = readonly
btn_remove.disabled = not removable
#func _process(delta):
# pass
func _on_btn_browse_pressed():
var dialog = FileDialog.new()
dialog.access = FileDialog.ACCESS_FILESYSTEM
dialog.mode = FileDialog.MODE_OPEN_DIR
dialog.connect("dir_selected", self, "set_directory")
add_child(dialog)
dialog.popup(Rect2(0, 0, 800, 600))
func _on_btn_remove_pressed():
set_directory("")

View File

@ -0,0 +1,30 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://scenes/DirectorySettingsEntry.gd" type="Script" id=1]
[node name="DirectorySettingsEntry" type="HBoxContainer"]
margin_top = 18.0
margin_right = 1080.0
margin_bottom = 42.0
script = ExtResource( 1 )
[node name="le_directory" type="LineEdit" parent="."]
margin_right = 937.0
margin_bottom = 24.0
rect_min_size = Vector2( 480, 1.36422e-12 )
size_flags_horizontal = 3
[node name="btn_browse" type="Button" parent="."]
margin_left = 941.0
margin_right = 1012.0
margin_bottom = 24.0
text = "Browse..."
[node name="btn_remove" type="Button" parent="."]
margin_left = 1016.0
margin_right = 1080.0
margin_bottom = 24.0
text = "Remove"
[connection signal="pressed" from="btn_browse" to="." method="_on_btn_browse_pressed"]
[connection signal="pressed" from="btn_remove" to="." method="_on_btn_remove_pressed"]

View File

@ -37,7 +37,6 @@ margin_top = 548.0
margin_right = 653.0
margin_bottom = 616.0
size_flags_horizontal = 4
disabled = true
text = "Settings"
[node name="btn_quit" type="Button" parent="VBoxContainer"]
@ -56,4 +55,5 @@ align = 1
[connection signal="pressed" from="VBoxContainer/btn_touch" to="." method="_on_btn_touch_pressed"]
[connection signal="pressed" from="VBoxContainer/btn_step" to="." method="_on_btn_step_pressed"]
[connection signal="pressed" from="VBoxContainer/btn_settings" to="." method="_on_btn_settings_pressed"]
[connection signal="pressed" from="VBoxContainer/btn_quit" to="." method="quit"]

11
scenes/RadialGame.gd Normal file
View File

@ -0,0 +1,11 @@
extends AspectRatioContainer
signal exit_mode
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=21 format=2]
[gd_scene load_steps=22 format=2]
[ext_resource path="res://scripts/NoteViewport.gd" type="Script" id=1]
[ext_resource path="res://assets/text-4k.png" type="Texture" id=2]
@ -13,6 +13,7 @@
[ext_resource path="res://shaders/receptors.shader" type="Shader" id=11]
[ext_resource path="res://shaders/notemesh.shader" type="Shader" id=12]
[ext_resource path="res://shaders/notelines.shader" type="Shader" id=13]
[ext_resource path="res://scenes/RadialGame.gd" type="Script" id=14]
[sub_resource type="ShaderMaterial" id=1]
shader = ExtResource( 11 )
@ -83,6 +84,7 @@ _data = [ Vector2( -1, -1 ), 0.0, 0.0, 0, 0, Vector2( 0, 0 ), 2.0, 2.0, 1, 1, Ve
[node name="RadialGame" type="AspectRatioContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 14 )
[node name="square" type="Control" parent="."]
unique_name_in_owner = true

58
scenes/SettingsMenu.gd Normal file
View File

@ -0,0 +1,58 @@
extends Control
const DirectorySettingsEntry = preload('res://scenes/DirectorySettingsEntry.tscn')
onready var container_folders = $'%container_folders'
signal exit_mode
var paths = []
var path_entries := []
# Called when the node enters the scene tree for the first time.
func _ready():
paths = Array(Settings.get_library_paths())
generate_entries()
func generate_entries():
paths.append("")
for entry in path_entries:
container_folders.remove_child(entry)
path_entries = []
for path in paths:
var entry = DirectorySettingsEntry.instance()
entry.connect('path_updated', self, '_entry_updated', [len(path_entries)])
path_entries.append(entry)
entry.directory = path
container_folders.add_child(entry)
path_entries[0].removable = false
path_entries[0].readonly = true
func get_paths_from_entries() -> Array:
var paths := []
for entry in path_entries:
var dir = entry.directory
if dir:
paths.append(entry.directory)
return paths
func _save_settings():
var paths = get_paths_from_entries()
var user_path: String = paths[0]
var extra_paths: Array = paths.slice(1, -1)
Settings.set_additional_library_paths(extra_paths)
func _entry_updated(new_path: String, index: int):
paths = get_paths_from_entries()
if (index == len(path_entries)-1):
if new_path:
generate_entries()
elif not new_path:
generate_entries()
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass
func _on_btn_back_pressed():
_save_settings()
emit_signal('exit_mode')

32
scenes/SettingsMenu.tscn Normal file
View File

@ -0,0 +1,32 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://scenes/SettingsMenu.gd" type="Script" id=2]
[node name="SettingsMenu" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 2 )
[node name="VBoxContainer" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
[node name="Label" type="Label" parent="VBoxContainer"]
margin_right = 1080.0
margin_bottom = 14.0
text = "Resource Folders"
align = 1
[node name="container_folders" type="VBoxContainer" parent="VBoxContainer"]
unique_name_in_owner = true
margin_top = 18.0
margin_right = 1080.0
margin_bottom = 18.0
[node name="btn_back" type="Button" parent="VBoxContainer"]
margin_top = 22.0
margin_right = 1080.0
margin_bottom = 42.0
text = "Back"
[connection signal="pressed" from="VBoxContainer/btn_back" to="." method="_on_btn_back_pressed"]

12
scenes/StepGame.gd Normal file
View File

@ -0,0 +1,12 @@
extends Control
signal exit_mode
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=16 format=2]
[gd_scene load_steps=17 format=2]
[ext_resource path="res://scripts/NoteViewport.gd" type="Script" id=1]
[ext_resource path="res://assets/text-4k.png" type="Texture" id=2]
@ -7,6 +7,7 @@
[ext_resource path="res://scenes/StepMenu.tscn" type="PackedScene" id=5]
[ext_resource path="res://scripts/NoteHandler.gd" type="Script" id=6]
[ext_resource path="res://assets/fonts/Sniglet-Regular.ttf" type="DynamicFontData" id=7]
[ext_resource path="res://scenes/StepGame.gd" type="Script" id=8]
[ext_resource path="res://scripts/ScreenFilter.gd" type="Script" id=9]
[ext_resource path="res://shaders/notemesh.shader" type="Shader" id=12]
[ext_resource path="res://shaders/notelines.shader" type="Shader" id=13]
@ -62,6 +63,7 @@ blend_mode = 4
[node name="StepGame" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 8 )
[node name="video" type="TextureRect" parent="." groups=["VideoTexRects"]]
anchor_right = 1.0

View File

@ -92,6 +92,8 @@ static func find_by_extensions(array, extensions=null) -> Dictionary:
static func init_directory(directory: String):
var dir = Directory.new()
var err = dir.make_dir_recursive(directory)
if err == ERR_ALREADY_EXISTS: # API changed?
err = OK
if err != OK:
print('An error occurred while trying to create the directory: ', directory, err, ERROR_CODES[err])
return err

View File

@ -1,6 +1,7 @@
extends Control
signal start_touchgame
signal start_stepgame
signal open_settings
func update_libraries_text() -> void:
$lbl_settingspath.text = 'Data directories:\n' + '\n'.join(Settings.get_library_paths())
@ -17,3 +18,6 @@ func _on_btn_touch_pressed() -> void:
func _on_btn_step_pressed() -> void:
emit_signal('start_stepgame')
func _on_btn_settings_pressed():
emit_signal('open_settings')

View File

@ -62,7 +62,7 @@ func scan_library() -> Dictionary:
var rootdir = root + 'songs'
var dir = Directory.new()
var err = dir.make_dir_recursive(rootdir)
if err != OK:
if err != OK and err != ERR_ALREADY_EXISTS:
print_debug('An error occurred while trying to create the songs directory: ', err)
return err

View File

@ -5,6 +5,31 @@ extends Node
signal config_loaded
signal subsampling_changed(xy)
# Newer Android versions require storage access permissions to be requested at runtime.
# There is no way around this, so this code needs to be updated to work.
var android_permissions_granted := false
const REQUIRED_ANDROID_PERMISSIONS := PoolStringArray(['MANAGE_EXTERNAL_FILES', 'READ_EXTERNAL_FILES', 'WRITE_EXTERNAL_FILES'])
func check_android_permissions() -> bool:
if self.android_permissions_granted:
return true
var permissions_granted := OS.get_granted_permissions()
for perm in REQUIRED_ANDROID_PERMISSIONS:
if not (perm in permissions_granted):
return false
self.android_permissions_granted = true
return true
func update_android_permissions() -> void:
if not OS.has_feature('Android'):
return
if self.check_android_permissions():
return
OS.request_permissions()
func _on_request_permissions_result(permission: String, granted: bool) -> void:
print('_on_request_permissions_result: %s = %s' % [permission, granted])
# if granted and (permission in REQUIRED_ANDROID_PERMISSIONS):
# self.call_deferred('update_view')
const ANDROID_USERDIR := '/storage/emulated/0/RhythmGame/'
# The following would probably work. One huge caveat is that permission needs to be manually granted by the user in app settings as we can't use OS.request_permission('WRITE_EXTERNAL_STORAGE')
# '/storage/emulated/0/Android/data/au.ufeff.rhythmgame/'
@ -44,6 +69,10 @@ func get_library_paths() -> PoolStringArray:
paths.append(p.rstrip('/')+'/')
return PoolStringArray(paths)
func set_additional_library_paths(entries):
config.set_value('libraries', 'additional_paths', PoolStringArray(entries))
save_settings()
func load_settings():
config = ConfigFile.new()
config.set_value('libraries', 'additional_paths', [])
@ -64,3 +93,5 @@ func save_settings():
func _ready():
load_settings()
get_tree().connect('on_request_permissions_result', self, '_on_request_permissions_result')
self.update_android_permissions()