Initial Code for volume app based on NUI 41/287241/4 accepted/tizen/unified/20230202.015258
authortarun.mahay <tarun.mahay@samsung.com>
Wed, 25 Jan 2023 11:18:09 +0000 (16:48 +0530)
committertarun.mahay <tarun.mahay@samsung.com>
Tue, 31 Jan 2023 05:35:58 +0000 (11:05 +0530)
Change-Id: Id277167e771288cfa3df0974b68b74958c369ad7
Signed-off-by: tarun.mahay <tarun.mahay@samsung.com>
27 files changed:
.gitignore [new file with mode: 0644]
LICENSE [new file with mode: 0644]
NOTICE [new file with mode: 0644]
VolumeApp/Common/AppCommon.cs [new file with mode: 0644]
VolumeApp/Common/Resources.cs [new file with mode: 0644]
VolumeApp/Common/ScreenSizeUtils.cs [new file with mode: 0644]
VolumeApp/Common/ThemeUtility.cs [new file with mode: 0644]
VolumeApp/Core/ViewManager.cs [new file with mode: 0644]
VolumeApp/Views/MainView.cs [new file with mode: 0644]
VolumeApp/VolumeApp.cs [new file with mode: 0644]
VolumeApp/VolumeApp.csproj [new file with mode: 0644]
VolumeApp/VolumeApp.sln [new file with mode: 0644]
VolumeApp/res/Images/Mute_icon.png [new file with mode: 0644]
VolumeApp/res/Images/Playback_slider.png [new file with mode: 0644]
VolumeApp/res/Images/Volume_1-33.png [new file with mode: 0644]
VolumeApp/res/Images/Volume_34-66.png [new file with mode: 0644]
VolumeApp/res/Images/Volume_67-100.png [new file with mode: 0644]
VolumeApp/res/Images/dark/button_outline.png [new file with mode: 0644]
VolumeApp/res/Images/dark/thumb_dark.png [new file with mode: 0644]
VolumeApp/res/Images/light/button_outline.png [new file with mode: 0644]
VolumeApp/res/Images/light/thumb_light.png [new file with mode: 0644]
VolumeApp/res/themes/dark.xaml [new file with mode: 0644]
VolumeApp/res/themes/light.xaml [new file with mode: 0644]
VolumeApp/shared/res/org.tizen.volume.png [new file with mode: 0644]
VolumeApp/tizen-manifest.xml [new file with mode: 0644]
packaging/org.tizen.volume-nui-1.0.0.tpk [new file with mode: 0644]
packaging/org.tizen.volume-nui.spec [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..b7551fe
--- /dev/null
@@ -0,0 +1,4 @@
+VolumeApp/.vs/
+VolumeApp/bin/
+VolumeApp/obj/
+VolumeApp/VolumeApp.csproj.user
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..4559fcc
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,204 @@
+Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/NOTICE b/NOTICE
new file mode 100644 (file)
index 0000000..f24d86a
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,3 @@
+Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the LICENSE file for Apache License terms and conditions.
\ No newline at end of file
diff --git a/VolumeApp/Common/AppCommon.cs b/VolumeApp/Common/AppCommon.cs
new file mode 100644 (file)
index 0000000..91ac297
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using Tizen.NUI;
+namespace VolumeApp.Common
+{
+    static class AppCommon
+    {
+        public static Vector4 mainViewCornerRadius = new Vector4(12.0f, 12.0f, 12.0f, 12.0f);
+        public static Extents mainViewPadding = new Extents(20, 20, 20, 20).SpToPx();
+        public static Shadow mainViewLightBoxShadow = new Shadow(0.0f, new Color(0, 0, 0, 0.16f), new Vector2(0, 2));
+        public static Shadow mainViewDarkBoxShadow = new Shadow(0.0f, new Color(1.0f, 1.0f, 1.0f, 0.5f), new Vector2(0, 2));
+        public static int mainViewWidth = 104.SpToPx();
+
+        public static Vector4 sliderCornerRadius = new Vector4(8, 8, 8, 8);
+        public static Size2D sliderThumbSizeNormal = new Size2D(24, 24).SpToPx();
+        public static Size2D sliderThumbSizePressed = new Size2D(40, 40).SpToPx();
+        public static int sliderWidth = 16.SpToPx();
+        public static float sliderPaddingRatioPortrait = 0.059f;
+        public static float sliderPaddingRatioLandscape = 0.075f;
+
+        public static Extents volumeIconMargin = new Extents(0, 0, 20, 0).SpToPx();
+        public static Size2D iconSize = new Size2D(48, 48).SpToPx();
+        public static Size2D buttonSize = new Size2D(252, 48).SpToPx();
+        public static Vector4 buttonCornerRadius = new Vector4(12.0f, 12.0f, 12.0f, 12.0f);
+    }
+}
diff --git a/VolumeApp/Common/Resources.cs b/VolumeApp/Common/Resources.cs
new file mode 100644 (file)
index 0000000..9a95a62
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace VolumeApp.Common
+{
+    public static class Resources
+    {
+        public const string LightPlatformThemeId = "org.tizen.default-light-theme";
+        public const string DarkPlatformThemeId = "org.tizen.default-dark-theme";
+        public const string LogTag = "VOLUME_APP";
+        public static string ImageDir = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "Images/";
+        public static string MuteIconPath = ImageDir + "Mute_icon.png";
+        public static string Volume1_33IconPath = ImageDir + "Volume_1-33.png";
+        public static string Volume34_66IconPath = ImageDir + "Volume_34-66.png";
+        public static string Volume67_100IconPath = ImageDir + "Volume_67-100.png";
+        public static string GetThemePath()
+        {
+            return Tizen.Applications.Application.Current.DirectoryInfo.Resource + "themes/";
+        }
+    }
+}
diff --git a/VolumeApp/Common/ScreenSizeUtils.cs b/VolumeApp/Common/ScreenSizeUtils.cs
new file mode 100644 (file)
index 0000000..7faed23
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using Tizen.NUI;
+
+namespace VolumeApp.Common
+{
+    public static class ScreenSizeUtils
+    {
+        public static bool IsPortrait => Window.Instance.Size.Height > Window.Instance.Size.Width;
+        public static int Height => Window.Instance.Size.Height;
+        public static int Width => Window.Instance.Size.Width;
+    }
+}
diff --git a/VolumeApp/Common/ThemeUtility.cs b/VolumeApp/Common/ThemeUtility.cs
new file mode 100644 (file)
index 0000000..65ab1b8
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using Tizen.NUI;
+using System.IO;
+using System;
+using Tizen.NUI.Xaml;
+
+namespace VolumeApp.Common
+{
+    class ThemeUtility
+    {
+        private Theme theme;
+
+        private static ThemeUtility instance = null;
+        private ThemeUtility()
+        {
+            ThemeManager.ThemeChanged += OnThemeChanged;
+        }
+
+        public static ThemeUtility GetInstance()
+        {
+            if(instance == null)
+            {
+                instance = new ThemeUtility();
+            }
+            return instance;
+        }
+
+
+        public void UpdateTheme(string platformThemeId)
+        {
+            if (platformThemeId == null)
+            {
+                Tizen.Log.Error(Resources.LogTag, "Platform theme id is null");
+                return;
+            }
+            if (platformThemeId.Equals(Resources.LightPlatformThemeId))
+            {
+                SetTheme(Resources.GetThemePath() + "light.xaml");
+            }
+            else if (platformThemeId.Equals(Resources.DarkPlatformThemeId))
+            {
+                SetTheme(Resources.GetThemePath() + "dark.xaml");
+            }
+        }
+
+        public void Clear()
+        {
+            ThemeManager.ThemeChanged -= OnThemeChanged;
+            theme.Clear();
+            instance = null;
+        }
+        private void SetTheme(string path)
+        {
+            try
+            {
+                theme = new Theme(path);
+                ThemeManager.ApplyTheme(theme);
+            }
+            catch (ArgumentNullException e)
+            {
+                Tizen.Log.Error(Resources.LogTag, "ArgumentNullException: " + e.ParamName);
+            }
+            catch (IOException e)
+            {
+                Tizen.Log.Error(Resources.LogTag, "IOException: " + e.Message);
+            }
+            catch (XamlParseException e)
+            {
+                Tizen.Log.Error(Resources.LogTag, "XamlParseException: " + e.Message);
+                if (e.XmlInfo != null)
+                {
+                    Tizen.Log.Error(Resources.LogTag, "XamlParseException, LineNo." + e.XmlInfo.LineNumber + " Pos: " + e.XmlInfo.LinePosition + " HasInfo: " + e.XmlInfo.HasLineInfo().ToString());
+                }
+            }
+        }
+        private void OnThemeChanged(object sender, ThemeChangedEventArgs e)
+        {
+            if (e.IsPlatformThemeChanged)
+            {
+                Tizen.Log.Info(Resources.LogTag, "Theme Changed: " + e.ThemeId);
+                UpdateTheme(ThemeManager.PlatformThemeId);
+            }
+        }
+    }
+}
diff --git a/VolumeApp/Core/ViewManager.cs b/VolumeApp/Core/ViewManager.cs
new file mode 100644 (file)
index 0000000..22bd01f
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using VolumeApp.Common;
+using VolumeApp.Views;
+namespace VolumeApp.Core
+{
+    public class ViewManager : Disposable
+    {
+        private MainView mainView;
+        private Timer volumeAppAutoHideTimer;
+        private Window window;
+        public ViewManager()
+        {
+            window = Window.Instance;
+
+            ThemeUtility.GetInstance().UpdateTheme(ThemeManager.PlatformThemeId);
+
+            mainView = new MainView();
+            window.Add(mainView);
+
+            volumeAppAutoHideTimer = new Timer(4000);
+            volumeAppAutoHideTimer.Start();
+            volumeAppAutoHideTimer.Tick += OnTimerTick;
+
+            mainView.TouchEvent += OnMainViewTouched;
+            mainView.SliderSlidingStarted += OnSliderSlidingStarted;
+            mainView.SliderSlidingFinished += OnSliderSlidingFinished;
+            mainView.SafeVolumeLevelPopupAdded += OnSafeLevelVolumePopupAdded;
+            mainView.SafeVolumeLevelPopupRemoved += OnSafeLevelVolumePopupRemoved;
+
+            Window.Instance.KeyEvent += OnKeyEvent;
+        }
+
+        public void UpdateMainView()
+        {
+            mainView.UpdateMainView();
+        }
+
+        protected override void Dispose(DisposeTypes type)
+        {
+            if (Disposed)
+            {
+                return;
+            }
+
+            if (type == DisposeTypes.Explicit)
+            {
+                Window.Instance.KeyEvent -= OnKeyEvent;
+
+                volumeAppAutoHideTimer.Tick -= OnTimerTick;
+                volumeAppAutoHideTimer?.Dispose();
+
+                mainView.TouchEvent -= OnMainViewTouched;
+                mainView.SliderSlidingStarted -= OnSliderSlidingStarted;
+                mainView.SliderSlidingFinished -= OnSliderSlidingFinished;
+                mainView.SafeVolumeLevelPopupAdded -= OnSafeLevelVolumePopupAdded;
+                mainView.SafeVolumeLevelPopupRemoved -= OnSafeLevelVolumePopupRemoved;
+
+                window.Remove(mainView);
+                mainView?.Dispose();
+
+                ThemeUtility.GetInstance().Clear();
+            }
+            base.Dispose(type);
+        }
+        private void OnKeyEvent(object sender, Window.KeyEventArgs e)
+        {
+
+        if (e.Key.KeyPressedName == "XF86AudioLowerVolume")
+        {
+            if (e.Key.State == Key.StateType.Down)
+            {
+                mainView.DecreaseSliderValue();
+                volumeAppAutoHideTimer.Stop();
+                Window.Instance.Show();
+            }
+            else if (e.Key.State == Key.StateType.Up)
+            {
+                if (!mainView.IsAlertPopupShown())
+                {
+                    volumeAppAutoHideTimer.Start();
+                }
+            }
+        }
+        else if (e.Key.KeyPressedName == "XF86AudioRaiseVolume")
+        {
+            if (e.Key.State == Key.StateType.Down)
+            {
+                mainView.IncreaseSliderValue();
+                volumeAppAutoHideTimer.Stop();
+                Window.Instance.Show();
+            }
+            else if (e.Key.State == Key.StateType.Up)
+            {
+                if (!mainView.IsAlertPopupShown())
+                {
+                    volumeAppAutoHideTimer.Start();
+                }
+            }
+        }
+        }
+        private void StartTimer()
+        {
+            volumeAppAutoHideTimer?.Start();
+        }
+        private void StopTimer()
+        {
+            volumeAppAutoHideTimer?.Stop();
+        }
+        private void OnSafeLevelVolumePopupRemoved()
+        {
+            StartTimer();
+            mainView.TouchEvent += OnMainViewTouched;
+        }
+        private void OnSafeLevelVolumePopupAdded()
+        {
+            StopTimer();
+            mainView.TouchEvent -= OnMainViewTouched;
+        }
+        private void OnSliderSlidingFinished()
+        {
+            Tizen.Log.Debug(Resources.LogTag, "Sliding finished start timer.");
+            StartTimer();
+        }
+        private void OnSliderSlidingStarted()
+        {
+            Tizen.Log.Debug(Resources.LogTag, "Sliding started stop timer.");
+            StopTimer();
+        }
+        private bool OnMainViewTouched(object source, View.TouchEventArgs e)
+        {
+            if (e.Touch.GetState(0) == PointStateType.Finished
+                || e.Touch.GetState(0) == PointStateType.Interrupted)
+            {
+                StartTimer();
+            }
+            else
+            {
+                StopTimer();
+            }
+            return true;
+        }
+        private bool OnTimerTick(object source, Timer.TickEventArgs e)
+        {
+            StopTimer();
+            Window.Instance.Hide();
+            return true;
+        }
+    }
+ }
+
diff --git a/VolumeApp/Views/MainView.cs b/VolumeApp/Views/MainView.cs
new file mode 100644 (file)
index 0000000..03a776f
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using Tizen.NUI;
+using Tizen.NUI.Components;
+using Tizen.Multimedia;
+using Tizen.NUI.BaseComponents;
+using VolumeApp.Common;
+
+namespace VolumeApp.Views
+{
+    class MainView : View
+    {
+        private float MaxVolume = AudioManager.VolumeController.MaxLevel[AudioVolumeType.Media];
+        private Slider slider;
+        private ImageView volumeIcon;
+        private AlertDialog safeVolumeLevelPopup;
+        private Button cancelButton;
+        private Button increaseButton;
+        private bool safetyModeEnabled;
+
+        public event Action SliderSlidingStarted;
+        public event Action SliderSlidingFinished;
+        public event Action SafeVolumeLevelPopupAdded;
+        public event Action SafeVolumeLevelPopupRemoved;
+        public MainView()
+        {
+            StyleName = "MainViewBackground";
+
+            WidthSpecification = AppCommon.mainViewWidth;
+            HeightSpecification = (ScreenSizeUtils.IsPortrait ? ScreenSizeUtils.Width : ScreenSizeUtils.Height) / 2;
+
+            Position2D = UpdatePosition();
+
+            Layout = new RelativeLayout()
+            {
+                Padding = AppCommon.mainViewPadding,
+            };
+            CornerRadius = AppCommon.mainViewCornerRadius;
+            volumeIcon = new ImageView()
+            {
+                Margin = AppCommon.volumeIconMargin,
+                Size2D = AppCommon.iconSize,
+                BackgroundColor = Color.Transparent,
+            };
+            Add(volumeIcon);
+
+            RelativeLayout.SetHorizontalAlignment(volumeIcon, RelativeLayout.Alignment.Center);
+            RelativeLayout.SetVerticalAlignment(volumeIcon, RelativeLayout.Alignment.End);
+
+            slider = new Slider()
+            {
+                StyleName = "Slider",
+                ThemeChangeSensitive = true,
+                WidthSpecification = AppCommon.sliderWidth,
+                Direction = Slider.DirectionType.Vertical,
+                CornerRadius = AppCommon.sliderCornerRadius,
+                ThumbSize = AppCommon.sliderThumbSizeNormal,
+                MinValue = 0.0f,
+                MaxValue = MaxVolume,
+                CurrentValue = AudioManager.VolumeController.Level[AudioVolumeType.Media],
+            };
+
+            safetyModeEnabled = slider.CurrentValue <= 0.9f * MaxVolume;
+            volumeIcon.ResourceUrl = SetVolumeIcon(slider.CurrentValue);
+            Add(slider);
+
+            RelativeLayout.SetBottomTarget(slider, volumeIcon);
+            RelativeLayout.SetBottomRelativeOffset(slider, 0.0f);
+            RelativeLayout.SetVerticalAlignment(slider, RelativeLayout.Alignment.Start);
+            RelativeLayout.SetHorizontalAlignment(slider, RelativeLayout.Alignment.Center);
+            RelativeLayout.SetFillVertical(slider, true);
+
+            slider.SlidingStarted += OnSlidingStarted;
+            slider.ValueChanged += OnSliderValueChanged;
+            slider.SlidingFinished += OnSlidingFinished;
+
+        }
+
+        public void IncreaseSliderValue()
+        {
+            if (slider.IsEnabled && slider.CurrentValue < 15)
+            {
+                slider.CurrentValue += 1;
+            }
+        }
+        public void DecreaseSliderValue()
+        {
+            if (slider.IsEnabled && slider.CurrentValue > 0)
+            {
+                slider.CurrentValue -= 1;
+            }
+        }
+
+        public bool IsAlertPopupShown()
+        {
+            return safeVolumeLevelPopup != null && safeVolumeLevelPopup.IsOnWindow;
+        }
+
+        private void UpdateTheme(string theme)
+        {
+            if (theme == Resources.LightPlatformThemeId)
+            {
+                BoxShadow = AppCommon.mainViewLightBoxShadow;
+            }
+            else
+            {
+                BoxShadow = AppCommon.mainViewDarkBoxShadow;
+            }
+        }
+
+        protected override void Dispose(DisposeTypes type)
+        {
+            if(Disposed)
+            {
+                return;
+            }
+
+            if(type == DisposeTypes.Explicit)
+            {
+
+                SliderSlidingStarted = null;
+                SliderSlidingFinished = null;
+                SafeVolumeLevelPopupAdded = null;
+                SafeVolumeLevelPopupRemoved = null;
+
+                slider.SlidingStarted -= OnSlidingStarted;
+                slider.ValueChanged -= OnSliderValueChanged;
+                slider.SlidingFinished -= OnSlidingFinished;
+
+                Remove(slider);
+                slider?.Dispose();
+
+                Remove(volumeIcon);
+                volumeIcon?.Dispose();
+                if(safeVolumeLevelPopup != null)
+                {
+                    cancelButton.Clicked -= OnCancelButtonClicked;
+                    increaseButton.Clicked -= OnIncreaseButtonClicked;
+                    Window.Instance.Remove(safeVolumeLevelPopup);
+                    safeVolumeLevelPopup?.Dispose();
+                }
+            }
+            base.Dispose(type);
+        }
+        public void UpdateMainView()
+        {
+            UpdateAlertPopUp();
+            Position2D = UpdatePosition();
+        }
+
+        private void UpdateAlertPopUp()
+        {
+            if(IsAlertPopupShown() == true)
+            {
+                Window.Instance.Remove(safeVolumeLevelPopup);
+                Window.Instance.Add(safeVolumeLevelPopup);
+            }
+        }
+        private Position2D UpdatePosition()
+        {
+            int posX = ScreenSizeUtils.IsPortrait
+                ? ScreenSizeUtils.Width - ((int)(ScreenSizeUtils.Width * AppCommon.sliderPaddingRatioPortrait)) - AppCommon.mainViewWidth
+                : ScreenSizeUtils.Width - ((int)(ScreenSizeUtils.Width * AppCommon.sliderPaddingRatioLandscape)) - AppCommon.mainViewWidth;
+
+            int posY = (ScreenSizeUtils.Height - (int)SizeHeight) / 2;
+            return new Position2D(posX, posY);
+        }
+
+        private void OnSlidingStarted(object sender, SliderSlidingStartedEventArgs e)
+        {
+            SliderSlidingStarted?.Invoke();
+            slider.ThumbSize = AppCommon.sliderThumbSizePressed;
+        }
+        private void OnSlidingFinished(object sender, SliderSlidingFinishedEventArgs e)
+        {
+            SliderSlidingFinished?.Invoke();
+            slider.ThumbSize = AppCommon.sliderThumbSizeNormal;
+        }
+        private void OnSliderValueChanged(object sender, SliderValueChangedEventArgs e)
+        {
+            if (e.CurrentValue > 0.9f * MaxVolume && safetyModeEnabled == true)
+            {
+                int safeVolumeLevel = (int)(0.9f * MaxVolume);
+                slider.CurrentValue = safeVolumeLevel;
+                slider.IsEnabled = false;
+                AudioManager.VolumeController.Level[AudioVolumeType.Media] = safeVolumeLevel;
+                AddSafeLevelVolumePopup();
+                return;
+            }
+
+            try
+            {
+                AudioManager.VolumeController.Level[AudioVolumeType.Media] = (int)e.CurrentValue;
+            }
+            catch (Exception ex)
+            {
+                Tizen.Log.Error(Resources.LogTag, "Exception thrown is : " + ex.Message);
+            }
+
+            volumeIcon.ResourceUrl = SetVolumeIcon(e.CurrentValue);
+
+        }
+        private void AddSafeLevelVolumePopup()
+        {
+            cancelButton = new Button("CancelButton")
+            {
+                Name = "CancelButton",
+                ThemeChangeSensitive = true,
+            };
+            increaseButton = new Button()
+            {
+                Size2D = AppCommon.buttonSize,
+                Text = "Increase",
+                CornerRadius = AppCommon.buttonCornerRadius,
+            };
+            if (safeVolumeLevelPopup == null)
+            {
+                safeVolumeLevelPopup = new AlertDialog()
+                {
+                    WidthSpecification = (int)((ScreenSizeUtils.IsPortrait ? ScreenSizeUtils.Height : ScreenSizeUtils.Width) * 0.36f),
+                    StyleName = "AlertDialogBackground",
+                    Title = "Increase media volume",
+                    Message = "Listening at a high volume for a long time may damage your hearing. The volume will be increased above safe levels.",
+                    Actions = new List<Button>() { cancelButton, increaseButton, },
+                };
+            }
+            safeVolumeLevelPopup.Content.WidthSpecification = LayoutParamPolicies.MatchParent;
+            safeVolumeLevelPopup.ActionContent.WidthSpecification = LayoutParamPolicies.MatchParent;
+            if (cancelButton.SizeWidth > safeVolumeLevelPopup.WidthSpecification / 2 - 40.SpToPx())
+            {
+                cancelButton.SizeWidth = (safeVolumeLevelPopup.WidthSpecification / 2) - 40.SpToPx();
+                increaseButton.SizeWidth = (safeVolumeLevelPopup.WidthSpecification / 2) - 40.SpToPx();
+
+            }
+            Window.Instance.Add(safeVolumeLevelPopup);
+            SafeVolumeLevelPopupAdded?.Invoke();
+
+            cancelButton.Clicked += OnCancelButtonClicked;
+            increaseButton.Clicked += OnIncreaseButtonClicked;
+        }
+
+        private void OnIncreaseButtonClicked(object sender, ClickedEventArgs e)
+        {
+            safetyModeEnabled = false;
+            slider.IsEnabled = true;
+            slider.ThumbSize = AppCommon.sliderThumbSizeNormal;
+            RemoveSafeVolumeLevelPopup();
+            AudioManager.VolumeController.Level[AudioVolumeType.Media] = (int)slider.CurrentValue;
+        }
+        private void OnCancelButtonClicked(object sender, ClickedEventArgs e)
+        {
+            slider.IsEnabled = true;
+            slider.ThumbSize = AppCommon.sliderThumbSizeNormal;
+            RemoveSafeVolumeLevelPopup();
+        }
+        private void RemoveSafeVolumeLevelPopup()
+        {
+            if (safeVolumeLevelPopup != null)
+            {
+                Window.Instance.Remove(safeVolumeLevelPopup);
+                SafeVolumeLevelPopupRemoved?.Invoke();
+            }
+        }
+        private string SetVolumeIcon(float currentVolume)
+        {
+            if (currentVolume == 0.0f)
+            {
+                return Resources.MuteIconPath;
+            }
+            else if (currentVolume <= 0.33 * MaxVolume)
+            {
+                return Resources.Volume1_33IconPath;
+            }
+            else if (currentVolume <= 0.66 * MaxVolume)
+            {
+                return Resources.Volume34_66IconPath;
+            }
+            else if (currentVolume <= MaxVolume)
+            {
+                return Resources.Volume67_100IconPath;
+            }
+            else
+            {
+                return Resources.Volume67_100IconPath;
+            }
+        }
+    }
+}
diff --git a/VolumeApp/VolumeApp.cs b/VolumeApp/VolumeApp.cs
new file mode 100644 (file)
index 0000000..7d09c1b
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Collections.Generic;
+using Tizen.Applications;
+using Tizen.NUI;
+using VolumeApp.Common;
+using VolumeApp.Core;
+
+namespace VolumeApp
+{
+
+    /// <summary>
+    /// VolumeApp is an Application which provide GUI to user to control sytem volume.
+    /// It displays an Alert popup, if user increses the volume beyond safe volume level
+    /// </summary>
+    class Program : NUIApplication
+    {
+        private Window window;
+        private ViewManager viewManager;
+
+        private const int KeyVolumeUp = 200;
+        private const int KeyVolumeDown = 201;
+
+        public Program() : base(ThemeOptions.PlatformThemeEnabled)
+        {
+        }
+        protected override void OnCreate()
+        {
+            base.OnCreate();
+
+            window = Window.Instance;
+
+            window.SetTransparency(true);
+            window.BackgroundColor = Color.Transparent;
+
+            ApplyWindowOrientation();
+
+            GrabKeys();
+
+            viewManager = new ViewManager();
+            window.Hide();
+            window.OrientationChanged += OnWindowOrientationChanged;
+        }
+
+        protected override void OnTerminate()
+        {
+            base.OnTerminate();
+            UnGrabKeys();
+
+            window.OrientationChanged -= OnWindowOrientationChanged;
+            viewManager.Dispose();
+            viewManager = null;
+        }
+
+        protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
+        {
+            base.OnAppControlReceived(e);
+            window?.Activate();
+        }
+        static void Main(string[] args)
+        {
+            var app = new Program();
+            app.Run(args);
+        }
+
+        private void ApplyWindowOrientation()
+        {
+            List<Window.WindowOrientation> list = new List<Window.WindowOrientation>
+            {
+                Window.WindowOrientation.Landscape,
+                Window.WindowOrientation.LandscapeInverse,
+                Window.WindowOrientation.NoOrientationPreference,
+                Window.WindowOrientation.Portrait,
+                Window.WindowOrientation.PortraitInverse,
+            };
+
+            window.SetAvailableOrientations(list);
+        }
+
+        private void GrabKeys()
+        {
+            if (false == window.GrabKey(KeyVolumeUp, Window.KeyGrabMode.Shared))
+            {
+                Tizen.Log.Error(Resources.LogTag, "Failed to GrabKey " + KeyVolumeUp);
+            }
+
+            if (false == window.GrabKey(KeyVolumeDown, Window.KeyGrabMode.Shared))
+            {
+                Tizen.Log.Error(Resources.LogTag, "Failed to GrabKey " + KeyVolumeDown);
+            }
+        }
+
+        private void UnGrabKeys()
+        {
+            if (false == window.UngrabKey(KeyVolumeUp))
+            {
+                Tizen.Log.Error(Resources.LogTag, "Failed to UnGrabKey " + KeyVolumeUp);
+            }
+
+            if (false == window.UngrabKey(KeyVolumeDown))
+            {
+                Tizen.Log.Error(Resources.LogTag, "Failed to UnGrabKey " + KeyVolumeDown);
+            }
+        }
+
+        private void OnWindowOrientationChanged(object sender, WindowOrientationChangedEventArgs e)
+        {
+            Tizen.Log.Debug(Resources.LogTag, "Current orientation is: " + e.WindowOrientation);
+            viewManager.UpdateMainView();
+        }
+
+    }
+}
+
+
diff --git a/VolumeApp/VolumeApp.csproj b/VolumeApp/VolumeApp.csproj
new file mode 100644 (file)
index 0000000..7dfd4fc
--- /dev/null
@@ -0,0 +1,36 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+       <PropertyGroup>
+               <OutputType>Exe</OutputType>
+               <TargetFramework>tizen11.0</TargetFramework>
+               <LangVersion>8.0</LangVersion>
+               <TargetFrameworkIdentifier>Tizen</TargetFrameworkIdentifier>
+       </PropertyGroup>
+
+       <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+               <DebugType>portable</DebugType>
+       </PropertyGroup>
+       <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+               <DebugType>None</DebugType>
+       </PropertyGroup>
+
+       <ItemGroup>
+               <PackageReference Include="Tizen.NET" Version="11.0.0.17657" />
+               <PackageReference Include="Tizen.NET.Sdk" Version="1.1.9" />
+       </ItemGroup>
+
+       <ItemGroup>
+         <Folder Include="res\Images\light\" />
+         <Folder Include="res\Images\dark\" />
+       </ItemGroup>
+
+       <ItemGroup>
+         <None Update="res\themes\dark.xaml">
+           <Generator>MSBuild:Compile</Generator>
+         </None>
+         <None Update="res\themes\light.xaml">
+           <Generator>MSBuild:Compile</Generator>
+         </None>
+       </ItemGroup>
+
+</Project>
diff --git a/VolumeApp/VolumeApp.sln b/VolumeApp/VolumeApp.sln
new file mode 100644 (file)
index 0000000..7102ff4
--- /dev/null
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31613.86
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VolumeApp", "VolumeApp.csproj", "{7B48E118-018F-4E05-A9E9-6103E0874F46}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {7B48E118-018F-4E05-A9E9-6103E0874F46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {7B48E118-018F-4E05-A9E9-6103E0874F46}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {7B48E118-018F-4E05-A9E9-6103E0874F46}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {7B48E118-018F-4E05-A9E9-6103E0874F46}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {81A72E4C-D738-4CE6-9739-7D55174BD32F}
+       EndGlobalSection
+EndGlobal
diff --git a/VolumeApp/res/Images/Mute_icon.png b/VolumeApp/res/Images/Mute_icon.png
new file mode 100644 (file)
index 0000000..b5ab239
Binary files /dev/null and b/VolumeApp/res/Images/Mute_icon.png differ
diff --git a/VolumeApp/res/Images/Playback_slider.png b/VolumeApp/res/Images/Playback_slider.png
new file mode 100644 (file)
index 0000000..dd8ed3f
Binary files /dev/null and b/VolumeApp/res/Images/Playback_slider.png differ
diff --git a/VolumeApp/res/Images/Volume_1-33.png b/VolumeApp/res/Images/Volume_1-33.png
new file mode 100644 (file)
index 0000000..549cc6a
Binary files /dev/null and b/VolumeApp/res/Images/Volume_1-33.png differ
diff --git a/VolumeApp/res/Images/Volume_34-66.png b/VolumeApp/res/Images/Volume_34-66.png
new file mode 100644 (file)
index 0000000..bb9bf33
Binary files /dev/null and b/VolumeApp/res/Images/Volume_34-66.png differ
diff --git a/VolumeApp/res/Images/Volume_67-100.png b/VolumeApp/res/Images/Volume_67-100.png
new file mode 100644 (file)
index 0000000..d5a3747
Binary files /dev/null and b/VolumeApp/res/Images/Volume_67-100.png differ
diff --git a/VolumeApp/res/Images/dark/button_outline.png b/VolumeApp/res/Images/dark/button_outline.png
new file mode 100644 (file)
index 0000000..38c2323
Binary files /dev/null and b/VolumeApp/res/Images/dark/button_outline.png differ
diff --git a/VolumeApp/res/Images/dark/thumb_dark.png b/VolumeApp/res/Images/dark/thumb_dark.png
new file mode 100644 (file)
index 0000000..78e0b85
Binary files /dev/null and b/VolumeApp/res/Images/dark/thumb_dark.png differ
diff --git a/VolumeApp/res/Images/light/button_outline.png b/VolumeApp/res/Images/light/button_outline.png
new file mode 100644 (file)
index 0000000..bbbabcc
Binary files /dev/null and b/VolumeApp/res/Images/light/button_outline.png differ
diff --git a/VolumeApp/res/Images/light/thumb_light.png b/VolumeApp/res/Images/light/thumb_light.png
new file mode 100644 (file)
index 0000000..bfaec8a
Binary files /dev/null and b/VolumeApp/res/Images/light/thumb_light.png differ
diff --git a/VolumeApp/res/themes/dark.xaml b/VolumeApp/res/themes/dark.xaml
new file mode 100644 (file)
index 0000000..82ac334
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Theme
+xmlns="http://tizen.org/Tizen.NUI/2018/XAML"
+xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+xmlns:c="clr-namespace:Tizen.NUI.Components;assembly=Tizen.NUI.Components"
+Id="DarkTheme">
+
+       <ViewStyle x:Key="MainViewBackground" BackgroundColor="#16131A" ThemeChangeSensitive="true" />
+       <c:AlertDialogStyle x:Key="AlertDialogBackground" ThemeChangeSensitive="true" BackgroundColor="#16131A">
+               <c:AlertDialogStyle.TitleTextLabel>
+                       <TextLabelStyle TextColor="#FDFDFD" FontFamily="BreezeSans" PixelSize="24sp" />
+               </c:AlertDialogStyle.TitleTextLabel>
+               <c:AlertDialogStyle.MessageTextLabel>
+                       <TextLabelStyle TextColor="#FDFDFD" FontFamily="BreezeSans" PixelSize="24sp" />
+               </c:AlertDialogStyle.MessageTextLabel>
+       </c:AlertDialogStyle>
+       <c:ButtonStyle x:Key="CancelButton" ThemeChangeSensitive="true" Size="252sp, 48sp" IsSelectable="false" IsEnabled="true" BackgroundColor="Transparent" >
+               <c:ButtonStyle.BackgroundImage>*Resource*/Images/dark/button_outline.png</c:ButtonStyle.BackgroundImage>
+               <c:ButtonStyle.Text>
+                       <TextLabelStyle TextColor="#FF8A00" FontFamily="BreezeSans" PixelSize="24sp" Text="Cancel" HorizontalAlignment="Center" VerticalAlignment="Center"/>
+               </c:ButtonStyle.Text>
+       </c:ButtonStyle>
+       <c:SliderStyle x:Key="Slider" >
+               <c:SliderStyle.Thumb>
+                       <ImageViewStyle>
+                               <ImageViewStyle.ResourceUrl>
+                                       <Selector x:TypeArguments="x:String" Normal="*Resource*/Images/dark/thumb_dark.png" />
+                               </ImageViewStyle.ResourceUrl>
+                       </ImageViewStyle>
+               </c:SliderStyle.Thumb>
+       </c:SliderStyle>
+</Theme>
\ No newline at end of file
diff --git a/VolumeApp/res/themes/light.xaml b/VolumeApp/res/themes/light.xaml
new file mode 100644 (file)
index 0000000..66ac353
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<Theme
+xmlns="http://tizen.org/Tizen.NUI/2018/XAML"
+xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+xmlns:c="clr-namespace:Tizen.NUI.Components;assembly=Tizen.NUI.Components"
+Id="LightTheme">
+
+    <ViewStyle x:Key="MainViewBackground" BackgroundColor="#FAFAFA" ThemeChangeSensitive="true" />
+    <c:AlertDialogStyle x:Key="AlertDialogBackground" ThemeChangeSensitive="true" BackgroundColor="#FAFAFA">
+        <c:AlertDialogStyle.TitleTextLabel>
+            <TextLabelStyle TextColor="#090E21" FontFamily="BreezeSans" PixelSize="24sp" />
+        </c:AlertDialogStyle.TitleTextLabel>
+        <c:AlertDialogStyle.MessageTextLabel>
+            <TextLabelStyle TextColor="#090E21" FontFamily="BreezeSans" PixelSize="24sp" />
+        </c:AlertDialogStyle.MessageTextLabel>
+    </c:AlertDialogStyle>
+    <c:ButtonStyle x:Key="CancelButton" ThemeChangeSensitive="true" Size="252sp, 48sp" IsSelectable="false" IsEnabled="true" BackgroundColor="Transparent" >
+        <c:ButtonStyle.BackgroundImage>*Resource*/Images/light/button_outline.png</c:ButtonStyle.BackgroundImage>
+        <c:ButtonStyle.Text>
+            <TextLabelStyle TextColor="#FF6200" FontFamily="BreezeSans" PixelSize="24sp" Text="Cancel" HorizontalAlignment="Center" VerticalAlignment="Center"/>
+        </c:ButtonStyle.Text>
+    </c:ButtonStyle>
+    <c:SliderStyle x:Key="Slider" >
+      <c:SliderStyle.Thumb>
+        <ImageViewStyle>
+         <ImageViewStyle.ResourceUrl>
+            <Selector x:TypeArguments="x:String" Normal="*Resource*/Images/light/thumb_light.png" />
+            </ImageViewStyle.ResourceUrl>
+        </ImageViewStyle>
+      </c:SliderStyle.Thumb>
+    </c:SliderStyle>
+</Theme>
\ No newline at end of file
diff --git a/VolumeApp/shared/res/org.tizen.volume.png b/VolumeApp/shared/res/org.tizen.volume.png
new file mode 100644 (file)
index 0000000..63cb5d5
Binary files /dev/null and b/VolumeApp/shared/res/org.tizen.volume.png differ
diff --git a/VolumeApp/tizen-manifest.xml b/VolumeApp/tizen-manifest.xml
new file mode 100644 (file)
index 0000000..a474d8a
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest package="org.tizen.volume-nui" version="1.0.0" api-version="7.0" xmlns="http://tizen.org/ns/packages">
+    <profile name="common" />
+    <ui-application appid="org.tizen.volume-nui" exec="VolumeApp.dll" multiple="false" nodisplay="true" taskmanage="false" api-version="10" type="dotnet" launch_mode="single">
+        <label>VolumeApp</label>
+        <icon>VolumeApp.png</icon>
+        <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+        <splash-screens />
+    </ui-application>
+    <shortcut-list />
+    <privileges>
+        <privilege>http://tizen.org/privilege/keygrab</privilege>
+        <privilege>http://tizen.org/privilege/volume.set</privilege>
+    </privileges>
+    <dependencies />
+    <provides-appdefined-privileges />
+</manifest>
diff --git a/packaging/org.tizen.volume-nui-1.0.0.tpk b/packaging/org.tizen.volume-nui-1.0.0.tpk
new file mode 100644 (file)
index 0000000..046a4a2
Binary files /dev/null and b/packaging/org.tizen.volume-nui-1.0.0.tpk differ
diff --git a/packaging/org.tizen.volume-nui.spec b/packaging/org.tizen.volume-nui.spec
new file mode 100644 (file)
index 0000000..0c1f996
--- /dev/null
@@ -0,0 +1,34 @@
+Name:       org.tizen.volume-nui
+Summary:    org.tizen.volume-nui
+Version:    1.0.0
+Release:    1
+Group:      N/A
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+
+BuildRequires:  pkgconfig(libtzplatform-config)
+Requires(post):  /usr/bin/tpk-backend
+
+%define apps_name org.tizen.volume-nui
+%define preload_tpk_path %{TZ_SYS_RO_APP}/.preload-tpk
+
+%description
+profile/iot/apps/dotnet/volume-app
+This is the application to control the system volume.
+
+%prep
+%setup -q
+
+%build
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}/%{preload_tpk_path}
+install packaging/%{apps_name}-%{version}.tpk %{buildroot}/%{preload_tpk_path}/
+
+%post
+
+%files
+%defattr(-,root,root,-)
+%{preload_tpk_path}/*
+%license LICENSE