Added custom grid size support in config.json
- Added support for config.json - Added custom grid size support in config.json (see readme for instructions)
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6269b6df21455a244a60057eaa3ff7af
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace QuestAppLauncher
|
||||
{
|
||||
/// <summary>
|
||||
/// Root config object
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Grid size
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class GridSize
|
||||
{
|
||||
public int rows;
|
||||
public int cols;
|
||||
}
|
||||
|
||||
public GridSize gridSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class responsible for loading / saving config into a config.json file.
|
||||
/// </summary>
|
||||
public class ConfigPersistence
|
||||
{
|
||||
// File name of app name overrides
|
||||
const string ConfigFileName = "config.json";
|
||||
|
||||
/// <summary>
|
||||
/// Load config from file
|
||||
/// </summary>
|
||||
/// <param name="config">Config object that will be overwritten</param>
|
||||
static public void LoadConfig(Config config)
|
||||
{
|
||||
var configFilePath = Path.Combine(UnityEngine.Application.persistentDataPath, ConfigFileName);
|
||||
if (File.Exists(configFilePath))
|
||||
{
|
||||
Debug.Log("Found config file: " + configFilePath);
|
||||
var jsonConfig = File.ReadAllText(configFilePath);
|
||||
|
||||
try
|
||||
{
|
||||
JsonUtility.FromJsonOverwrite(jsonConfig, config);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Log(string.Format("Failed to read config: {0}", e.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save config to a file
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
static public void SaveConfig(Config config)
|
||||
{
|
||||
var configFilePath = Path.Combine(UnityEngine.Application.persistentDataPath, ConfigFileName);
|
||||
Debug.Log("Saving config file: " + configFilePath);
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(configFilePath, JsonUtility.ToJson(config, true));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Log(string.Format("Failed to read config: {0}", e.Message));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6884476ef6b801242904ff090df0fb84
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -25,12 +25,21 @@ namespace QuestAppLauncher
|
||||
// Extension search for icon overrides
|
||||
const string IconOverrideExtSearch = "*.jpg";
|
||||
|
||||
// Canvas game object
|
||||
public GameObject canvas;
|
||||
|
||||
// Scroll view game object
|
||||
public GameObject scrollView;
|
||||
|
||||
// Grid content game object
|
||||
public GameObject gridContent;
|
||||
|
||||
// App info GameObject (a cell in the grid content)
|
||||
public GameObject prefab;
|
||||
|
||||
// Configuration
|
||||
private Config config = new Config();
|
||||
|
||||
#region MonoBehaviour handler
|
||||
|
||||
void Start()
|
||||
@@ -41,6 +50,9 @@ namespace QuestAppLauncher
|
||||
// Initialize the core platform
|
||||
Core.AsyncInitialize();
|
||||
|
||||
// Load configuration
|
||||
StartCoroutine(ProcessConfig());
|
||||
|
||||
// Populate the grid
|
||||
StartCoroutine(Populate());
|
||||
}
|
||||
@@ -117,6 +129,65 @@ namespace QuestAppLauncher
|
||||
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads & processes config
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator ProcessConfig()
|
||||
{
|
||||
// Load config
|
||||
ConfigPersistence.LoadConfig(this.config);
|
||||
|
||||
ProcessGridSize();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
private void ProcessGridSize()
|
||||
{
|
||||
// Make sure grid size have sane value
|
||||
if (0 == this.config.gridSize.cols && 0 == this.config.gridSize.rows)
|
||||
{
|
||||
// If not initialized, default to 3x3
|
||||
this.config.gridSize.cols = 3;
|
||||
this.config.gridSize.rows = 3;
|
||||
}
|
||||
this.config.gridSize.cols = Math.Min(this.config.gridSize.cols, 10);
|
||||
this.config.gridSize.cols = Math.Max(this.config.gridSize.cols, 1);
|
||||
this.config.gridSize.rows = Math.Min(this.config.gridSize.rows, 50);
|
||||
this.config.gridSize.rows = Math.Max(this.config.gridSize.rows, 1);
|
||||
|
||||
// Get cell size, spacing & padding from the grid layout
|
||||
var gridLayoutGroup = this.gridContent.GetComponent<GridLayoutGroup>();
|
||||
var cellHeight = gridLayoutGroup.cellSize.y;
|
||||
var cellWidth = gridLayoutGroup.cellSize.x;
|
||||
var paddingX = gridLayoutGroup.padding.horizontal;
|
||||
var paddingY = gridLayoutGroup.padding.vertical;
|
||||
var spaceX = gridLayoutGroup.spacing.x;
|
||||
var spaceY = gridLayoutGroup.spacing.y;
|
||||
|
||||
// Width = horizontal padding + # cols * cell width + (# cols - 1) * horizontal spacing
|
||||
var width = paddingX + this.config.gridSize.cols * cellWidth + (this.config.gridSize.cols - 1) * spaceX;
|
||||
|
||||
// Height = vertical padding + # rows * cell height + (# rows - 1) * veritcal spacing + a bit more to show there are more elements
|
||||
var height = paddingY + this.config.gridSize.rows * cellHeight + (this.config.gridSize.rows - 1) * spaceY + 120;
|
||||
|
||||
Debug.Log(string.Format("Setting grid size to {0} x {1} cells", this.config.gridSize.cols, this.config.gridSize.rows));
|
||||
Debug.Log(string.Format("Grid size calculated width x height: {0} x {1}", width, height));
|
||||
|
||||
// Adjust canvas rect transform
|
||||
var canvasRectTransform = this.canvas.GetComponent<RectTransform>();
|
||||
canvasRectTransform.sizeDelta = new Vector2(width, height);
|
||||
|
||||
// Adjust scroll view rect transform
|
||||
var scrollViewRectTransform = this.scrollView.GetComponent<RectTransform>();
|
||||
scrollViewRectTransform.sizeDelta = new Vector2(width, height);
|
||||
|
||||
// Adjust scroll view box collider
|
||||
var scrollViewBoxCollider = this.scrollView.GetComponent<BoxCollider>();
|
||||
scrollViewBoxCollider.size = new Vector3(width, height, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populate the grid from installed apps
|
||||
/// </summary>
|
||||
|
||||
@@ -2,62 +2,65 @@
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class OnInteraction : MonoBehaviour
|
||||
namespace QuestAppLauncher
|
||||
{
|
||||
protected Material oldHoverMat;
|
||||
public Material yellowMat;
|
||||
public Material backIdle;
|
||||
public Material backACtive;
|
||||
public UnityEngine.UI.Text outText;
|
||||
|
||||
public void OnHoverEnter(Transform t)
|
||||
public class OnInteraction : MonoBehaviour
|
||||
{
|
||||
var appEntry = t.gameObject.GetComponent("AppEntry") as AppEntry;
|
||||
if (null != appEntry)
|
||||
protected Material oldHoverMat;
|
||||
public Material yellowMat;
|
||||
public Material backIdle;
|
||||
public Material backACtive;
|
||||
public UnityEngine.UI.Text outText;
|
||||
|
||||
public void OnHoverEnter(Transform t)
|
||||
{
|
||||
// Enable border
|
||||
EnableBorder(t, true);
|
||||
var appEntry = t.gameObject.GetComponent("AppEntry") as AppEntry;
|
||||
if (null != appEntry)
|
||||
{
|
||||
// Enable border
|
||||
EnableBorder(t, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnHoverExit(Transform t)
|
||||
{
|
||||
var appEntry = t.gameObject.GetComponent("AppEntry") as AppEntry;
|
||||
if (null != appEntry)
|
||||
{
|
||||
// Disable border
|
||||
EnableBorder(t, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSelected(Transform t)
|
||||
{
|
||||
var appEntry = t.gameObject.GetComponent("AppEntry") as AppEntry;
|
||||
if (null != appEntry)
|
||||
{
|
||||
// Launch app
|
||||
Debug.Log("Launching: " + appEntry.appName + " (package id: " + appEntry.packageId + ")");
|
||||
QuestAppLauncher.GridPopulation.LaunchApp(appEntry.packageId);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSelectedPressedBorY(Transform t)
|
||||
{
|
||||
var appEntry = t.gameObject.GetComponent("AppEntry") as AppEntry;
|
||||
if (null != appEntry)
|
||||
{
|
||||
// Add package name to excluded file
|
||||
Debug.Log("Hiding: " + appEntry.appName + " (package id: " + appEntry.packageId + ")");
|
||||
QuestAppLauncher.GridPopulation.AddAppToExcludedFile(appEntry.packageId);
|
||||
|
||||
// Remove ourselves from the gridview
|
||||
Destroy(t.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void EnableBorder(Transform t, bool enable)
|
||||
{
|
||||
var border = t.Find("Border");
|
||||
border?.gameObject.SetActive(enable);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnHoverExit(Transform t)
|
||||
{
|
||||
var appEntry = t.gameObject.GetComponent("AppEntry") as AppEntry;
|
||||
if (null != appEntry)
|
||||
{
|
||||
// Disable border
|
||||
EnableBorder(t, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSelected(Transform t)
|
||||
{
|
||||
var appEntry = t.gameObject.GetComponent("AppEntry") as AppEntry;
|
||||
if (null != appEntry)
|
||||
{
|
||||
// Launch app
|
||||
Debug.Log("Launching: " + appEntry.appName + " (package id: " + appEntry.packageId + ")");
|
||||
QuestAppLauncher.GridPopulation.LaunchApp(appEntry.packageId);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSelectedPressedBorY(Transform t)
|
||||
{
|
||||
var appEntry = t.gameObject.GetComponent("AppEntry") as AppEntry;
|
||||
if (null != appEntry)
|
||||
{
|
||||
// Add package name to excluded file
|
||||
Debug.Log("Hiding: " + appEntry.appName + " (package id: " + appEntry.packageId + ")");
|
||||
QuestAppLauncher.GridPopulation.AddAppToExcludedFile(appEntry.packageId);
|
||||
|
||||
// Remove ourselves from the gridview
|
||||
Destroy(t.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void EnableBorder(Transform t, bool enable)
|
||||
{
|
||||
var border = t.Find("Border");
|
||||
border?.gameObject.SetActive(enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,62 +3,65 @@ using System.Collections;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
public class ScrollRectOverride : ScrollRect, IMoveHandler, IPointerClickHandler, IScrollHandler
|
||||
namespace QuestAppLauncher
|
||||
{
|
||||
private const float speedMultiplier = 15f;
|
||||
private float cellHeight = 0f;
|
||||
|
||||
void Start()
|
||||
public class ScrollRectOverride : ScrollRect, IMoveHandler, IPointerClickHandler, IScrollHandler
|
||||
{
|
||||
this.cellHeight = this.transform.GetComponentInChildren<GridLayoutGroup>().cellSize.y;
|
||||
}
|
||||
private const float speedMultiplier = 15f;
|
||||
private float cellHeight = 0f;
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Get vector from either left or right thumbstick
|
||||
var moveVector = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick);
|
||||
if (moveVector.x == 0 && moveVector.y == 0)
|
||||
void Start()
|
||||
{
|
||||
moveVector = OVRInput.Get(OVRInput.Axis2D.SecondaryThumbstick);
|
||||
this.cellHeight = this.transform.GetComponentInChildren<GridLayoutGroup>().cellSize.y;
|
||||
}
|
||||
|
||||
// Scroll by a fixed amount proportional to thumbstick position on each frame
|
||||
// and map this to a fraction of the total viewport size:
|
||||
// moveVector.y: The thumbstick vertical position normalized to [-1,1].
|
||||
// Time.deltaTime: The time delta since last frame
|
||||
// speedMultiplier: Just a multiplier to get a good scrolling speed.
|
||||
// So, moveVector.y * Time.deltaTime * speedMultiplier = the amount to scroll in "units"
|
||||
// proportional to thumbstick position since last frame.
|
||||
// this.cellHeight / this.content.sizeDelta.y = cell height / total content height.
|
||||
float verticalIncrement = moveVector.y * Time.deltaTime * speedMultiplier * this.cellHeight / this.content.sizeDelta.y;
|
||||
this.verticalNormalizedPosition = Mathf.Clamp01(this.verticalNormalizedPosition + verticalIncrement);
|
||||
}
|
||||
void Update()
|
||||
{
|
||||
// Get vector from either left or right thumbstick
|
||||
var moveVector = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick);
|
||||
if (moveVector.x == 0 && moveVector.y == 0)
|
||||
{
|
||||
moveVector = OVRInput.Get(OVRInput.Axis2D.SecondaryThumbstick);
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData e)
|
||||
{
|
||||
}
|
||||
// Scroll by a fixed amount proportional to thumbstick position on each frame
|
||||
// and map this to a fraction of the total viewport size:
|
||||
// moveVector.y: The thumbstick vertical position normalized to [-1,1].
|
||||
// Time.deltaTime: The time delta since last frame
|
||||
// speedMultiplier: Just a multiplier to get a good scrolling speed.
|
||||
// So, moveVector.y * Time.deltaTime * speedMultiplier = the amount to scroll in "units"
|
||||
// proportional to thumbstick position since last frame.
|
||||
// this.cellHeight / this.content.sizeDelta.y = cell height / total content height.
|
||||
float verticalIncrement = moveVector.y * Time.deltaTime * speedMultiplier * this.cellHeight / this.content.sizeDelta.y;
|
||||
this.verticalNormalizedPosition = Mathf.Clamp01(this.verticalNormalizedPosition + verticalIncrement);
|
||||
}
|
||||
|
||||
public override void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
}
|
||||
public void OnPointerClick(PointerEventData e)
|
||||
{
|
||||
}
|
||||
|
||||
void IMoveHandler.OnMove(AxisEventData e)
|
||||
{
|
||||
}
|
||||
public override void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
}
|
||||
|
||||
void IScrollHandler.OnScroll(PointerEventData eventData)
|
||||
{
|
||||
}
|
||||
void IMoveHandler.OnMove(AxisEventData e)
|
||||
{
|
||||
}
|
||||
|
||||
void OnMouseDrag()
|
||||
{
|
||||
}
|
||||
void IScrollHandler.OnScroll(PointerEventData eventData)
|
||||
{
|
||||
}
|
||||
|
||||
void OnMouseUp()
|
||||
{
|
||||
}
|
||||
void OnMouseDrag()
|
||||
{
|
||||
}
|
||||
|
||||
void OnMouseDown()
|
||||
{
|
||||
void OnMouseUp()
|
||||
{
|
||||
}
|
||||
|
||||
void OnMouseDown()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,40 +3,42 @@ using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class SettingsHandler : MonoBehaviour
|
||||
namespace QuestAppLauncher
|
||||
{
|
||||
public GameObject scrollView;
|
||||
public GameObject openSettingsButton;
|
||||
public GameObject closeSettingsButton;
|
||||
public GameObject settingsView;
|
||||
|
||||
public void OpenSettings()
|
||||
public class SettingsHandler : MonoBehaviour
|
||||
{
|
||||
Debug.Log("Open Settings");
|
||||
scrollView.SetActive(false);
|
||||
openSettingsButton.SetActive(false);
|
||||
closeSettingsButton.SetActive(true);
|
||||
settingsView.SetActive(true);
|
||||
}
|
||||
public GameObject scrollView;
|
||||
public GameObject openSettingsButton;
|
||||
public GameObject closeSettingsButton;
|
||||
public GameObject settingsView;
|
||||
|
||||
public void CloseSettings()
|
||||
{
|
||||
Debug.Log("Close Settings");
|
||||
scrollView.SetActive(true);
|
||||
openSettingsButton.SetActive(true);
|
||||
closeSettingsButton.SetActive(false);
|
||||
settingsView.SetActive(false);
|
||||
}
|
||||
public void OpenSettings()
|
||||
{
|
||||
Debug.Log("Open Settings");
|
||||
scrollView.SetActive(false);
|
||||
openSettingsButton.SetActive(false);
|
||||
closeSettingsButton.SetActive(true);
|
||||
settingsView.SetActive(true);
|
||||
}
|
||||
|
||||
public void RefreshScene()
|
||||
{
|
||||
Debug.Log("Scene refreshed");
|
||||
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
|
||||
}
|
||||
public void CloseSettings()
|
||||
{
|
||||
Debug.Log("Close Settings");
|
||||
scrollView.SetActive(true);
|
||||
openSettingsButton.SetActive(true);
|
||||
closeSettingsButton.SetActive(false);
|
||||
settingsView.SetActive(false);
|
||||
}
|
||||
|
||||
public void DeleteExcludedApksFile()
|
||||
{
|
||||
Debug.Log("Delete Excluded Apk List");
|
||||
QuestAppLauncher.GridPopulation.DeleteExcludedApksFile();
|
||||
public void ResizeGrid(int selection)
|
||||
{
|
||||
Debug.Log("Resize grid: " + selection);
|
||||
}
|
||||
|
||||
public void DeleteExcludedApksFile()
|
||||
{
|
||||
Debug.Log("Delete Excluded Apk List");
|
||||
QuestAppLauncher.GridPopulation.DeleteExcludedApksFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,36 @@ An app launcher for Quest implemented in Unity.
|
||||
## Overriding app icons and names
|
||||
For each installed app, we extract the default app name (PackageManager.getApplicationLabel()) and default app icon (PackageManager.getApplicationIcon()). Sometimes, however, these do not map to the actual app name and icon in the Oculus Store. In order to override this, do the following:
|
||||
|
||||
1) Override app names: Create a file called appnames.txt. Add a line per app with comma-separated package-id and desired name. Example:
|
||||
# Override app names
|
||||
Create a file called **appnames.txt**. Add a line per app with comma-separated package-id and desired name. Example:
|
||||
appnames.txt:
|
||||
com.mycompany.myapp,My Application
|
||||
com.othercompany.otherapp,Other application
|
||||
|
||||
2) Override app icons: Create a jpg file per app with the package-id as the filename. Example:
|
||||
Copy this file (appnames.txt) to the following location on your Quest: Android/data/aaa.QuestAppLauncher.App/files
|
||||
|
||||
# Override app icons
|
||||
Create a jpg file per app with the package-id as the filename. Example:
|
||||
com.mycompany.myapp.jpg
|
||||
com.thirdcompany.yetanotherapp.jpg
|
||||
|
||||
Copy these files to the following location on your Quest: Android/data/aaa.QuestAppLauncher.App/files
|
||||
|
||||
3) Copy the above contents (appnames.txt + jpg files) to the following location on your Quest: Android/data/aaa.QuestAppLauncher.App/files
|
||||
## Configuration
|
||||
The app can be customized by creating a **config.json** file and copying it to the following location on your Quest: Android/data/aaa.QuestAppLauncher.App/files.
|
||||
|
||||
The following options are supported:
|
||||
# Setting Grid Size
|
||||
The default grid size is 3x3 cells. The grid size can be customer by specifying grid rows and columns as in the following example:
|
||||
|
||||
```
|
||||
{
|
||||
"gridSize": {
|
||||
"rows": 2,
|
||||
"cols": 4
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Source structure:
|
||||
- Assets/Scenes/QuestAppLauncher.unity: The main scene
|
||||
|
||||
Reference in New Issue
Block a user