From 90af803cc8213146fac29ff16d4a6f0c0792eb68 Mon Sep 17 00:00:00 2001 From: Peter Kirmeier Date: Sat, 9 Dec 2023 18:36:49 +0100 Subject: [PATCH] Initial Android support (It runs on Android but with very limited feature set) Refactor project files to support multiple platforms (Desktop and Android) Move and adjust resource names as Android only supports very limited paths and file names (drawable folder and no "-" allowed) Improve license generation keep license file readable (auto referenced NuGet packages and dual licenses) Simplify namespace names for XAML (c for common, v for view ...) Improved selection of the correct Assembly for reading resources or versions Split all Pages into Page and Window sources - Desktop applications will continue working with windows so they continue using the Windows classes - Android can only work with the new SingleViewNavigationPage which is always present and only switches between the Pages - The Pages are UserControls only now - The Windows are used for Desktop applications only and act as a wrapper for the Pages --- .../{icons8-24-64.png => icons8_24_64.png} | Bin ...flagpole-64.png => icons8_flagpole_64.png} | Bin Source/Datafiles/Designs/javascript.js | 6 +- Source/Directory.Build.props | 25 + Source/GenerateThirdPartyLicense.sh | 23 +- .../HitCounterManager.Android.csproj | 32 + .../HitCounterManager.Android.csproj.user | 9 + Source/HitCounterManager.Android/Icon.png | Bin 0 -> 14349 bytes .../HitCounterManager.Android/MainActivity.cs | 92 ++ .../Properties/AndroidManifest.xml | 5 + .../Resources/AboutResources.txt | 44 + .../drawable-night-v31/avalonia_anim.xml | 66 + .../Resources/drawable-v31/avalonia_anim.xml | 71 ++ .../Resources/drawable/splash_screen.xml | 13 + .../Resources/values-night/colors.xml | 4 + .../Resources/values-v31/styles.xml | 21 + .../Resources/values/colors.xml | 4 + .../Resources/values/styles.xml | 12 + .../HitCounterManager.Desktop.csproj | 21 + .../Program.cs | 91 +- Source/HitCounterManager.sln | 16 +- Source/HitCounterManager/Common/App.axaml | 199 ++- Source/HitCounterManager/Common/App.axaml.cs | 67 +- Source/HitCounterManager/Common/Extensions.cs | 29 +- Source/HitCounterManager/Common/Statics.cs | 23 +- Source/HitCounterManager/Common/Update.cs | 14 +- .../Controls/FramedImageButton.xaml | 4 +- .../Controls/ProfileView.xaml | 28 +- ...er.csproj => HitCounterManager.PCL.csproj} | 33 +- Source/HitCounterManager/Models/Shortcuts.cs | 3 +- .../Resources/drawable/FireIcon.png | Bin 0 -> 7249 bytes .../icons8_about_20.png} | Bin .../icons8_add_20.png} | Bin .../icons8_add_list_20.png} | Bin .../icons8_attack_32.png} | Bin .../icons8_circled_right_20.png} | Bin .../icons8_cloud_20.png} | Bin .../icons8_copy_20.png} | Bin .../icons8_counter_20.png} | Bin .../icons8_double_down_20.png} | Bin .../icons8_double_up_20.png} | Bin .../icons8_edit_20.png} | Bin .../icons8_empty_flag_20.png} | Bin .../icons8_flag_filled_20.png} | Bin .../icons8_flash_light_20.png} | Bin .../icons8_inactive_state_20.png} | Bin .../icons8_information_18.png} | Bin .../icons8_last_24_hours_20.png} | Bin .../icons8_lock_20.png} | Bin .../icons8_padlock_20.png} | Bin .../icons8_pin_20.png} | Bin .../icons8_repeat_one_32.png} | Bin .../icons8_save_20.png} | Bin .../icons8_scroll_down_20.png} | Bin .../icons8_scroll_up_20.png} | Bin .../icons8_search_in_browser_20.png} | Bin .../icons8_settings_20.png} | Bin .../icons8_sleep_32.png} | Bin .../icons8_staircase_32.png} | Bin .../icons8_time_32.png} | Bin .../icons8_trash_20.png} | Bin .../icons8_trophy_32.png} | Bin .../icons8_watch_your_step_32.png} | Bin .../icons8_website_20.png} | Bin .../team_hitless_20p_logo_black.png} | Bin .../ViewModels/MainPageViewModel.cs | 44 +- Source/HitCounterManager/Views/AboutPage.xaml | 39 +- .../HitCounterManager/Views/AboutPage.xaml.cs | 5 +- .../HitCounterManager/Views/AboutWindow.xaml | 33 + .../Views/AboutWindow.xaml.cs | 36 + ...Close.xaml => AskSaveBeforeClosePage.xaml} | 23 +- ...xaml.cs => AskSaveBeforeClosePage.xaml.cs} | 3 +- .../Views/AskSaveBeforeCloseWindow.xaml | 34 + .../Views/AskSaveBeforeCloseWindow.xaml.cs | 36 + Source/HitCounterManager/Views/MainPage.xaml | 92 +- .../HitCounterManager/Views/MainPage.xaml.cs | 22 +- .../HitCounterManager/Views/MainWindow.xaml | 34 + .../Views/MainWindow.xaml.cs | 62 + Source/HitCounterManager/Views/PageBase.cs | 111 ++ .../Views/ProfileActionPage.xaml | 46 +- .../Views/ProfileActionPage.xaml.cs | 5 +- .../Views/ProfileActionWindow.xaml | 33 + .../Views/ProfileActionWindow.xaml.cs | 36 + .../Views/ProfileAttemptsPage.xaml | 22 +- .../Views/ProfileAttemptsPage.xaml.cs | 5 +- .../Views/ProfileAttemptsWindow.xaml | 33 + .../Views/ProfileAttemptsWindow.xaml.cs | 36 + .../HitCounterManager/Views/SettingsPage.xaml | 119 +- .../Views/SettingsPage.xaml.cs | 5 +- .../Views/SettingsWindow.xaml | 33 + .../Views/SettingsWindow.xaml.cs | 36 + .../Views/SingleViewNavigationPage.xaml | 28 + .../Views/SingleViewNavigationPage.xaml.cs | 58 + .../HitCounterManager/Views/UpdatePage.xaml | 25 +- .../Views/UpdatePage.xaml.cs | 5 +- .../HitCounterManager/Views/UpdateWindow.xaml | 33 + .../Views/UpdateWindow.xaml.cs | 36 + .../{WindowPageBase.cs => WindowBase.cs} | 28 +- Source/azure-pipelines.yml | 41 +- THIRDPARTYLICENSEREADME | 1134 +++++++++++++++-- 100 files changed, 2679 insertions(+), 647 deletions(-) rename Source/Datafiles/Designs/{icons8-24-64.png => icons8_24_64.png} (100%) rename Source/Datafiles/Designs/{icons8-flagpole-64.png => icons8_flagpole_64.png} (100%) create mode 100644 Source/Directory.Build.props create mode 100644 Source/HitCounterManager.Android/HitCounterManager.Android.csproj create mode 100644 Source/HitCounterManager.Android/HitCounterManager.Android.csproj.user create mode 100644 Source/HitCounterManager.Android/Icon.png create mode 100644 Source/HitCounterManager.Android/MainActivity.cs create mode 100644 Source/HitCounterManager.Android/Properties/AndroidManifest.xml create mode 100644 Source/HitCounterManager.Android/Resources/AboutResources.txt create mode 100644 Source/HitCounterManager.Android/Resources/drawable-night-v31/avalonia_anim.xml create mode 100644 Source/HitCounterManager.Android/Resources/drawable-v31/avalonia_anim.xml create mode 100644 Source/HitCounterManager.Android/Resources/drawable/splash_screen.xml create mode 100644 Source/HitCounterManager.Android/Resources/values-night/colors.xml create mode 100644 Source/HitCounterManager.Android/Resources/values-v31/styles.xml create mode 100644 Source/HitCounterManager.Android/Resources/values/colors.xml create mode 100644 Source/HitCounterManager.Android/Resources/values/styles.xml create mode 100644 Source/HitCounterManager.Desktop/HitCounterManager.Desktop.csproj rename Source/{HitCounterManager/Common => HitCounterManager.Desktop}/Program.cs (92%) rename Source/HitCounterManager/{HitCounterManager.csproj => HitCounterManager.PCL.csproj} (60%) create mode 100644 Source/HitCounterManager/Resources/drawable/FireIcon.png rename Source/HitCounterManager/Resources/{Images/icons8-about-20.png => drawable/icons8_about_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-add-20.png => drawable/icons8_add_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-add-list-20.png => drawable/icons8_add_list_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-attack-32.png => drawable/icons8_attack_32.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-circled-right-20.png => drawable/icons8_circled_right_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-cloud-20.png => drawable/icons8_cloud_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-copy-20.png => drawable/icons8_copy_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-counter-20.png => drawable/icons8_counter_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-double-down-20.png => drawable/icons8_double_down_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-double-up-20.png => drawable/icons8_double_up_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-edit-20.png => drawable/icons8_edit_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-empty-flag-20.png => drawable/icons8_empty_flag_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-flag-filled-20.png => drawable/icons8_flag_filled_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-flash-light-20.png => drawable/icons8_flash_light_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-inactive-state-20.png => drawable/icons8_inactive_state_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-information-18.png => drawable/icons8_information_18.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-last-24-hours-20.png => drawable/icons8_last_24_hours_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-lock-20.png => drawable/icons8_lock_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-padlock-20.png => drawable/icons8_padlock_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-pin-20.png => drawable/icons8_pin_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-repeat-one-32.png => drawable/icons8_repeat_one_32.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-save-20.png => drawable/icons8_save_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-scroll-down-20.png => drawable/icons8_scroll_down_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-scroll-up-20.png => drawable/icons8_scroll_up_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-search-in-browser-20.png => drawable/icons8_search_in_browser_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-settings-20.png => drawable/icons8_settings_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-sleep-32.png => drawable/icons8_sleep_32.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-staircase-32.png => drawable/icons8_staircase_32.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-time-32.png => drawable/icons8_time_32.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-trash-20.png => drawable/icons8_trash_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-trophy-32.png => drawable/icons8_trophy_32.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-watch-your-step-32.png => drawable/icons8_watch_your_step_32.png} (100%) rename Source/HitCounterManager/Resources/{Images/icons8-website-20.png => drawable/icons8_website_20.png} (100%) rename Source/HitCounterManager/Resources/{Images/20p_logo_black.png => drawable/team_hitless_20p_logo_black.png} (100%) create mode 100644 Source/HitCounterManager/Views/AboutWindow.xaml create mode 100644 Source/HitCounterManager/Views/AboutWindow.xaml.cs rename Source/HitCounterManager/Views/{AskSaveBeforeClose.xaml => AskSaveBeforeClosePage.xaml} (73%) rename Source/HitCounterManager/Views/{AskSaveBeforeClose.xaml.cs => AskSaveBeforeClosePage.xaml.cs} (88%) create mode 100644 Source/HitCounterManager/Views/AskSaveBeforeCloseWindow.xaml create mode 100644 Source/HitCounterManager/Views/AskSaveBeforeCloseWindow.xaml.cs create mode 100644 Source/HitCounterManager/Views/MainWindow.xaml create mode 100644 Source/HitCounterManager/Views/MainWindow.xaml.cs create mode 100644 Source/HitCounterManager/Views/PageBase.cs create mode 100644 Source/HitCounterManager/Views/ProfileActionWindow.xaml create mode 100644 Source/HitCounterManager/Views/ProfileActionWindow.xaml.cs create mode 100644 Source/HitCounterManager/Views/ProfileAttemptsWindow.xaml create mode 100644 Source/HitCounterManager/Views/ProfileAttemptsWindow.xaml.cs create mode 100644 Source/HitCounterManager/Views/SettingsWindow.xaml create mode 100644 Source/HitCounterManager/Views/SettingsWindow.xaml.cs create mode 100644 Source/HitCounterManager/Views/SingleViewNavigationPage.xaml create mode 100644 Source/HitCounterManager/Views/SingleViewNavigationPage.xaml.cs create mode 100644 Source/HitCounterManager/Views/UpdateWindow.xaml create mode 100644 Source/HitCounterManager/Views/UpdateWindow.xaml.cs rename Source/HitCounterManager/Views/{WindowPageBase.cs => WindowBase.cs} (62%) diff --git a/Source/Datafiles/Designs/icons8-24-64.png b/Source/Datafiles/Designs/icons8_24_64.png similarity index 100% rename from Source/Datafiles/Designs/icons8-24-64.png rename to Source/Datafiles/Designs/icons8_24_64.png diff --git a/Source/Datafiles/Designs/icons8-flagpole-64.png b/Source/Datafiles/Designs/icons8_flagpole_64.png similarity index 100% rename from Source/Datafiles/Designs/icons8-flagpole-64.png rename to Source/Datafiles/Designs/icons8_flagpole_64.png diff --git a/Source/Datafiles/Designs/javascript.js b/Source/Datafiles/Designs/javascript.js index 0322b1f3..d93cec60 100644 --- a/Source/Datafiles/Designs/javascript.js +++ b/Source/Datafiles/Designs/javascript.js @@ -1,6 +1,6 @@ //MIT License -//Copyright (c) 2018-2022 Peter Kirmeier +//Copyright (c) 2018-2023 Peter Kirmeier //Permission is hereby granted, free of charge, to any person obtaining a copy //of this software and associated documentation files (the "Software"), to deal @@ -59,8 +59,8 @@ function IntToStringSigned(i) { if (i == 0) return '0'; else if (i > 0) return ' function ShowCrossOrCheckMark(i) { return ''; } -function ShowSessionProgress() { return ''; } -function ShowBestProgress() { return ''; } +function ShowSessionProgress() { return ''; } +function ShowBestProgress() { return ''; } function OffsetTimerTick() { if (offset_timer_tick_callback != undefined) offset_timer_tick_callback(Date.now() - offset_timer_start); } diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props new file mode 100644 index 00000000..da3f583f --- /dev/null +++ b/Source/Directory.Build.props @@ -0,0 +1,25 @@ + + + + 2.0.0.0 + HitCounterManager + + $(Version) + $(Version) + $(Product) + Manages a hit counter + en + + Peter Kirmeier + + Copyright © $(Authors) $([System.DateTime]::Now.Year) + + enable + + + + + + 11.0.5 + + diff --git a/Source/GenerateThirdPartyLicense.sh b/Source/GenerateThirdPartyLicense.sh index b3698c9e..1073b8b5 100644 --- a/Source/GenerateThirdPartyLicense.sh +++ b/Source/GenerateThirdPartyLicense.sh @@ -142,14 +142,16 @@ EOF echo Fetching NuGet packages 1>&2 LICENSES="" -NUGET_PACKAGES_DIR=$(dotnet nuget locals -l global-packages | sed -e 's,^[^ ]* ,,') -NUGET_PACKAGES_SPECS=$(dotnet list $(pwd)/HitCounterManager.sln package --include-transitive | grep ">" | sed -e 's,^[^>]*>[ \t]*\([^ ^\t]*\)[ \t]*\([^ ^\t]*\).*,\L\1/\2/\L\1.nuspec,' | xargs) +NUGET_PACKAGES_DIR=$(dotnet nuget locals -l global-packages | sed -e 's,^[^ ]* ,,' -e 's,[ \t/\\]*$,,' -e 's,\\,/,g') +NUGET_PACKAGES_SPECS=$(dotnet list $(pwd)/HitCounterManager.sln package --include-transitive --format json | grep -e '"id":\|"resolvedVersion":' | sed -e 's,.*: "\(.*\)"\,*$,\1,' | xargs -n2 -d'\n' | sed -e 's,\([^ ]*\) \(.*\),\L\1/\2/\L\1.nuspec,') echo Printing NuGet packages 1>&2 -for nuspec in ${NUGET_PACKAGES_SPECS}; +for nuspec in ${NUGET_PACKAGES_SPECS} do - xml="${NUGET_PACKAGES_DIR}/${nuspec}" + # (a) seems to be filler expression to whatever version is available, try detect folder using shell's star autocompletion + xml="$(echo ${NUGET_PACKAGES_DIR}/${nuspec} | sed -e 's,/(a)/,/*/,g')" + id=$(grepkey id "${xml}") echo ============================================================================== echo NuGet Package: ${id} $(grepkey version "${xml}") @@ -174,13 +176,20 @@ do if [ ! -z ${GITHUB_RAWURL} ] ; then lic=${GITHUB_RAWURL} fi - echo License: ${lic} - LICENSES="${LICENSES} ${lic}" + # Split dual licences + if [ "${lic}" = "https://licenses.nuget.org/MIT%20AND%20Apache-2.0" ] ; then + lic="https://licenses.nuget.org/MIT https://licenses.nuget.org/Apache-2.0" + fi + for lic in ${lic} + do + echo License: ${lic} + LICENSES="${LICENSES} ${lic}" + done done echo Printing NuGet licenses 1>&2 -for lic in $(echo $LICENSES | xargs -n 1 echo | sort -u) ; +for lic in $(echo $LICENSES | xargs -n 1 echo | sort -u) do if [ "${lic}" = "https://licenses.nuget.org/MIT" ] ; then # MIT is already attached above diff --git a/Source/HitCounterManager.Android/HitCounterManager.Android.csproj b/Source/HitCounterManager.Android/HitCounterManager.Android.csproj new file mode 100644 index 00000000..028a6e0c --- /dev/null +++ b/Source/HitCounterManager.Android/HitCounterManager.Android.csproj @@ -0,0 +1,32 @@ + + + + net7.0-android + + + Exe + $(Product).Android + + + 21 + com.peterkirmeier.$(Product) + 1 + 1.0 + apk + False + + + + + Resources\drawable\Icon.png + + + + + + + + + + + diff --git a/Source/HitCounterManager.Android/HitCounterManager.Android.csproj.user b/Source/HitCounterManager.Android/HitCounterManager.Android.csproj.user new file mode 100644 index 00000000..b31f0e2e --- /dev/null +++ b/Source/HitCounterManager.Android/HitCounterManager.Android.csproj.user @@ -0,0 +1,9 @@ + + + + pixel_5_-_api_34 + Emulator + Pixel 5 - API 34 (Android 14.0 - API 34) + pixel_5_-_api_34 + + \ No newline at end of file diff --git a/Source/HitCounterManager.Android/Icon.png b/Source/HitCounterManager.Android/Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..41a2a618fb02e4cb7f6a15caf572b693bfe1ebb1 GIT binary patch literal 14349 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 +{ + protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) + { + return base.CustomizeAppBuilder(builder) + .WithInterFont() + .UseReactiveUI(); + } +} + +/*using Android.App; +using Android.Content; +using Android.Content.PM; +using Android.Runtime; +using Avalonia; +using Avalonia.Android; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.ReactiveUI; +using HitCounterManager.Views; +using System.ComponentModel; + +namespace HitCounterManager.Android +{ + [Activity( + Label = "HitCounterManager.Android", + Theme = "@style/MyTheme.NoActionBar", + Icon = "@drawable/icon", + MainLauncher = true, + ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)] + public class MainActivity : AvaloniaMainActivity + { + protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) + { + return base.CustomizeAppBuilder(builder) + .WithInterFont() + .UseReactiveUI(); + } + + public override void OnBackPressed() + { + if (App.CurrentApp.ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) + { + // Return to previous page + SingleViewNavigationPage RootPage = (SingleViewNavigationPage)singleViewPlatform.MainView!; + if (1 < RootPage.NavStack.Count) + { + RootPage.PopPage(); + return; + } + + // Idea of stopping the process by defualt but this will popup the message box + // every time one is about the hit back button. Therefore it is better to keep + // the application running in backgroung. + // We will save the current state during OnStop(). +#if EXAMPLE_FORCED_SHUTDOWN + RootPage.MainPage.OnClosing(this, new CancelEventArgs()); + App.CurrentApp.AppExitHandler(this, null); + Finish(); +#endif + } + + base.OnBackPressed(); + } + + protected override void OnStop() + { + App.CurrentApp.SaveSettings(); + base.OnStop(); + } + + protected override void OnDestroy() + { + App.CurrentApp.AppExitHandler(this, new()); + base.OnDestroy(); + } + } +} +*/ \ No newline at end of file diff --git a/Source/HitCounterManager.Android/Properties/AndroidManifest.xml b/Source/HitCounterManager.Android/Properties/AndroidManifest.xml new file mode 100644 index 00000000..f6717fa2 --- /dev/null +++ b/Source/HitCounterManager.Android/Properties/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/Source/HitCounterManager.Android/Resources/AboutResources.txt b/Source/HitCounterManager.Android/Resources/AboutResources.txt new file mode 100644 index 00000000..4cededee --- /dev/null +++ b/Source/HitCounterManager.Android/Resources/AboutResources.txt @@ -0,0 +1,44 @@ +Images, layout descriptions, binary blobs and string dictionaries can be included +in your application as resource files. Various Android APIs are designed to +operate on the resource IDs instead of dealing with images, strings or binary blobs +directly. + +For example, a sample Android app that contains a user interface layout (main.axml), +an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) +would keep its resources in the "Resources" directory of the application: + +Resources/ + drawable/ + icon.png + + layout/ + main.axml + + values/ + strings.xml + +In order to get the build system to recognize Android resources, set the build action to +"AndroidResource". The native Android APIs do not operate directly with filenames, but +instead operate on resource IDs. When you compile an Android application that uses resources, +the build system will package the resources for distribution and generate a class called "R" +(this is an Android convention) that contains the tokens for each one of the resources +included. For example, for the above Resources layout, this is what the R class would expose: + +public class R { + public class drawable { + public const int icon = 0x123; + } + + public class layout { + public const int main = 0x456; + } + + public class strings { + public const int first_string = 0xabc; + public const int second_string = 0xbcd; + } +} + +You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main +to reference the layout/main.axml file, or R.strings.first_string to reference the first +string in the dictionary file values/strings.xml. \ No newline at end of file diff --git a/Source/HitCounterManager.Android/Resources/drawable-night-v31/avalonia_anim.xml b/Source/HitCounterManager.Android/Resources/drawable-night-v31/avalonia_anim.xml new file mode 100644 index 00000000..1fef3acf --- /dev/null +++ b/Source/HitCounterManager.Android/Resources/drawable-night-v31/avalonia_anim.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/HitCounterManager.Android/Resources/drawable-v31/avalonia_anim.xml b/Source/HitCounterManager.Android/Resources/drawable-v31/avalonia_anim.xml new file mode 100644 index 00000000..4784f80d --- /dev/null +++ b/Source/HitCounterManager.Android/Resources/drawable-v31/avalonia_anim.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/HitCounterManager.Android/Resources/drawable/splash_screen.xml b/Source/HitCounterManager.Android/Resources/drawable/splash_screen.xml new file mode 100644 index 00000000..4cebfe2c --- /dev/null +++ b/Source/HitCounterManager.Android/Resources/drawable/splash_screen.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/Source/HitCounterManager.Android/Resources/values-night/colors.xml b/Source/HitCounterManager.Android/Resources/values-night/colors.xml new file mode 100644 index 00000000..0f6f6c8c --- /dev/null +++ b/Source/HitCounterManager.Android/Resources/values-night/colors.xml @@ -0,0 +1,4 @@ + + + #212121 + diff --git a/Source/HitCounterManager.Android/Resources/values-v31/styles.xml b/Source/HitCounterManager.Android/Resources/values-v31/styles.xml new file mode 100644 index 00000000..8075ffad --- /dev/null +++ b/Source/HitCounterManager.Android/Resources/values-v31/styles.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/Source/HitCounterManager.Android/Resources/values/colors.xml b/Source/HitCounterManager.Android/Resources/values/colors.xml new file mode 100644 index 00000000..6fbae256 --- /dev/null +++ b/Source/HitCounterManager.Android/Resources/values/colors.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + diff --git a/Source/HitCounterManager.Android/Resources/values/styles.xml b/Source/HitCounterManager.Android/Resources/values/styles.xml new file mode 100644 index 00000000..77ed2d72 --- /dev/null +++ b/Source/HitCounterManager.Android/Resources/values/styles.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/Source/HitCounterManager.Desktop/HitCounterManager.Desktop.csproj b/Source/HitCounterManager.Desktop/HitCounterManager.Desktop.csproj new file mode 100644 index 00000000..cde16da5 --- /dev/null +++ b/Source/HitCounterManager.Desktop/HitCounterManager.Desktop.csproj @@ -0,0 +1,21 @@ + + + + net7.0 + + + WinExe + $(Product).Desktop + + win;linux;osx + true + ../$(Product)/Resources/FireIcon.ico + + + + + + + + + diff --git a/Source/HitCounterManager/Common/Program.cs b/Source/HitCounterManager.Desktop/Program.cs similarity index 92% rename from Source/HitCounterManager/Common/Program.cs rename to Source/HitCounterManager.Desktop/Program.cs index babdf389..c95a29a3 100644 --- a/Source/HitCounterManager/Common/Program.cs +++ b/Source/HitCounterManager.Desktop/Program.cs @@ -1,45 +1,46 @@ -//MIT License - -//Copyright (c) 2022-2022 Peter Kirmeier - -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files (the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions: - -//The above copyright notice and this permission notice shall be included in all -//copies or substantial portions of the Software. - -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -//SOFTWARE. - -using Avalonia; -using Avalonia.ReactiveUI; -using System; - -namespace HitCounterManager -{ - class Program - { - // Initialization code. Don't use any Avalonia, third-party APIs or any - // SynchronizationContext-reliant code before AppMain is called: things aren't initialized - // yet and stuff might break. - [STAThread] - public static void Main(string[] args) => BuildAvaloniaApp() - .StartWithClassicDesktopLifetime(args); - - // Avalonia configuration, don't remove; also used by visual designer. - public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() - .UsePlatformDetect() - .LogToTrace() - .UseReactiveUI(); - } -} +//MIT License + +//Copyright (c) 2022-2023 Peter Kirmeier + +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: + +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. + +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. + +using Avalonia; +using Avalonia.ReactiveUI; +using System; + +namespace HitCounterManager.Desktop +{ + class Program + { + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace() + .UseReactiveUI(); + } +} diff --git a/Source/HitCounterManager.sln b/Source/HitCounterManager.sln index 40bb688f..8aace530 100644 --- a/Source/HitCounterManager.sln +++ b/Source/HitCounterManager.sln @@ -3,7 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31611.283 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HitCounterManager", "HitCounterManager\HitCounterManager.csproj", "{BCD87D6B-3F73-46BA-B87E-0977A3D1CAD4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HitCounterManager", "HitCounterManager\HitCounterManager.PCL.csproj", "{BCD87D6B-3F73-46BA-B87E-0977A3D1CAD4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HitCounterManager.Desktop", "HitCounterManager.Desktop\HitCounterManager.Desktop.csproj", "{D69295AA-7BD6-46EC-8482-FB089246B91E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HitCounterManager.Android", "HitCounterManager.Android\HitCounterManager.Android.csproj", "{044A623F-CE8A-4694-A999-F80F02C09666}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -17,6 +21,16 @@ Global {BCD87D6B-3F73-46BA-B87E-0977A3D1CAD4}.Release|Any CPU.ActiveCfg = Release|Any CPU {BCD87D6B-3F73-46BA-B87E-0977A3D1CAD4}.Release|Any CPU.Build.0 = Release|Any CPU {BCD87D6B-3F73-46BA-B87E-0977A3D1CAD4}.Release|Any CPU.Deploy.0 = Release|Any CPU + {D69295AA-7BD6-46EC-8482-FB089246B91E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D69295AA-7BD6-46EC-8482-FB089246B91E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D69295AA-7BD6-46EC-8482-FB089246B91E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D69295AA-7BD6-46EC-8482-FB089246B91E}.Release|Any CPU.Build.0 = Release|Any CPU + {044A623F-CE8A-4694-A999-F80F02C09666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {044A623F-CE8A-4694-A999-F80F02C09666}.Debug|Any CPU.Build.0 = Debug|Any CPU + {044A623F-CE8A-4694-A999-F80F02C09666}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {044A623F-CE8A-4694-A999-F80F02C09666}.Release|Any CPU.ActiveCfg = Release|Any CPU + {044A623F-CE8A-4694-A999-F80F02C09666}.Release|Any CPU.Build.0 = Release|Any CPU + {044A623F-CE8A-4694-A999-F80F02C09666}.Release|Any CPU.Deploy.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/HitCounterManager/Common/App.axaml b/Source/HitCounterManager/Common/App.axaml index 31da015e..4a032dd7 100644 --- a/Source/HitCounterManager/Common/App.axaml +++ b/Source/HitCounterManager/Common/App.axaml @@ -24,8 +24,7 @@ --> @@ -69,112 +68,112 @@ Beige - - /Resources/Images/icons8-trash-20.png - - - /Resources/Images/icons8-search-in-browser-20.png - - - /Resources/Images/icons8-information-18.png - + + /Resources/drawable/icons8_trash_20.png + + + /Resources/drawable/icons8_search_in_browser_20.png + + + /Resources/drawable/icons8_information_18.png + - - /Resources/Images/icons8-inactive-state-20.png - - - /Resources/Images/icons8-circled-right-20.png - - - /Resources/Images/icons8-last-24-hours-20.png - - - /Resources/Images/icons8-empty-flag-20.png - - - /Resources/Images/icons8-flag-filled-20.png - + + /Resources/drawable/icons8_inactive_state_20.png + + + /Resources/drawable/icons8_circled_right_20.png + + + /Resources/drawable/icons8_last_24_hours_20.png + + + /Resources/drawable/icons8_empty_flag_20.png + + + /Resources/drawable/icons8_flag_filled_20.png + - - /Resources/Images/icons8-settings-20.png - - - /Resources/Images/icons8-save-20.png - - - /Resources/Images/icons8-website-20.png - - - /Resources/Images/20p_logo_black.png - - - /Resources/Images/icons8-cloud-20.png - - - /Resources/Images/icons8-about-20.png - + + /Resources/drawable/icons8_settings_20.png + + + /Resources/drawable/icons8_save_20.png + + + /Resources/drawable/icons8_website_20.png + + + /Resources/drawable/team_hitless_20p_logo_black.png + + + /Resources/drawable/icons8_cloud_20.png + + + /Resources/drawable/icons8_about_20.png + - - /Resources/Images/icons8-add-20.png - - - /Resources/Images/icons8-edit-20.png - - - /Resources/Images/icons8-copy-20.png - + + /Resources/drawable/icons8_add_20.png + + + /Resources/drawable/icons8_edit_20.png + + + /Resources/drawable/icons8_copy_20.png + - - /Resources/Images/icons8-counter-20.png - - - /Resources/Images/icons8-scroll-up-20.png - - - /Resources/Images/icons8-scroll-down-20.png - - - /Resources/Images/icons8-add-list-20.png - + + /Resources/drawable/icons8_counter_20.png + + + /Resources/drawable/icons8_scroll_up_20.png + + + /Resources/drawable/icons8_scroll_down_20.png + + + /Resources/drawable/icons8_add_list_20.png + - - /Resources/Images/icons8-lock-20.png - - - /Resources/Images/icons8-padlock-20.png - - - /Resources/Images/icons8-pin-20.png - - - /Resources/Images/icons8-flash-light-20.png - + + /Resources/drawable/icons8_lock_20.png + + + /Resources/drawable/icons8_padlock_20.png + + + /Resources/drawable/icons8_pin_20.png + + + /Resources/drawable/icons8_flash_light_20.png + - - /Resources/Images/icons8-repeat-one-32.png - - - /Resources/Images/icons8-trophy-32.png - - - /Resources/Images/icons8-sleep-32.png - - - /Resources/Images/icons8-time-32.png - - - /Resources/Images/icons8-attack-32.png - - - /Resources/Images/icons8-watch-your-step-32.png - - - /Resources/Images/icons8-staircase-32.png - + + /Resources/drawable/icons8_repeat_one_32.png + + + /Resources/drawable/icons8_trophy_32.png + + + /Resources/drawable/icons8_sleep_32.png + + + /Resources/drawable/icons8_time_32.png + + + /Resources/drawable/icons8_attack_32.png + + + /Resources/drawable/icons8_watch_your_step_32.png + + + /Resources/drawable/icons8_staircase_32.png + - + @@ -197,7 +196,7 @@ - +