├── .gitattributes
├── .github
├── FUNDING.yml
├── dependabot.yml
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
└── workflows
│ └── mobile.yml
├── AsyncCommandSample.iOS
├── Resources
│ ├── Default.png
│ ├── Default@2x.png
│ ├── Default-568h@2x.png
│ ├── Default-Portrait.png
│ ├── Default-Portrait@2x.png
│ └── LaunchScreen.storyboard
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ ├── Icon120.png
│ │ ├── Icon152.png
│ │ ├── Icon167.png
│ │ ├── Icon180.png
│ │ ├── Icon20.png
│ │ ├── Icon29.png
│ │ ├── Icon40.png
│ │ ├── Icon58.png
│ │ ├── Icon60.png
│ │ ├── Icon76.png
│ │ ├── Icon80.png
│ │ ├── Icon87.png
│ │ ├── Icon1024.png
│ │ └── Contents.json
├── Entitlements.plist
├── Main.cs
├── AppDelegate.cs
├── Info.plist
├── Properties
│ └── AssemblyInfo.cs
└── AsyncCommandSample.iOS.csproj
├── AsyncCommandSample.Android
├── Resources
│ ├── mipmap-hdpi
│ │ ├── icon.png
│ │ └── launcher_foreground.png
│ ├── mipmap-mdpi
│ │ ├── icon.png
│ │ └── launcher_foreground.png
│ ├── mipmap-xhdpi
│ │ ├── icon.png
│ │ └── launcher_foreground.png
│ ├── mipmap-xxhdpi
│ │ ├── icon.png
│ │ └── launcher_foreground.png
│ ├── mipmap-xxxhdpi
│ │ ├── icon.png
│ │ └── launcher_foreground.png
│ ├── mipmap-anydpi-v26
│ │ ├── icon.xml
│ │ └── icon_round.xml
│ ├── values
│ │ ├── colors.xml
│ │ └── styles.xml
│ └── AboutResources.txt
├── Properties
│ ├── AndroidManifest.xml
│ └── AssemblyInfo.cs
├── Assets
│ └── AboutAssets.txt
├── MainActivity.cs
└── AsyncCommandSample.Android.csproj
├── AsyncCommandSample
├── App.cs
├── Models
│ └── GitHubReleasesModel.cs
├── AsyncCommandSample.csproj
├── ViewModels
│ ├── BaseViewModel.cs
│ └── XamarinCommunityToolkitInfoViewModel.cs
└── Pages
│ └── XamarinCommunityToolkitInfoPage.cs
├── Directory.Build.props
├── AsyncCommandSample.UnitTests
├── AsyncCommandSample.UnitTests.csproj
├── Tests
│ └── XamarinCommunityToolkitInfoViewModelTests.cs
└── Mocks
│ └── MockPreferences.cs
├── LICENSE
├── README.md
├── AsyncCommandSample.sln
└── .gitignore
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [brminnick]
4 |
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Resources/Default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Resources/Default.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Resources/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Resources/Default@2x.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Resources/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Resources/Default-568h@2x.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Resources/Default-Portrait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Resources/Default-Portrait.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Resources/Default-Portrait@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Resources/Default-Portrait@2x.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-hdpi/icon.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-mdpi/icon.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-xhdpi/icon.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-xxhdpi/icon.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-xxxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-xxxhdpi/icon.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-hdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-hdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-mdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-mdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-xhdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-xhdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-xxhdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-xxhdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheCodeTraveler/AsyncCommandSample/HEAD/AsyncCommandSample.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Main.cs:
--------------------------------------------------------------------------------
1 | using UIKit;
2 |
3 | namespace AsyncCommandSample.iOS
4 | {
5 | public class Application
6 | {
7 | static void Main(string[] args) => UIApplication.Main(args, null, typeof(AppDelegate));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/AsyncCommandSample/App.cs:
--------------------------------------------------------------------------------
1 | using Xamarin.Essentials.Implementation;
2 | using Xamarin.Forms;
3 |
4 | namespace AsyncCommandSample
5 | {
6 | public class App : Application
7 | {
8 | public App() => MainPage = new XamarinCommunityToolkitInfoPage(new MainThreadImplementation());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-anydpi-v26/icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/mipmap-anydpi-v26/icon_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 | #3F51B5
5 | #303F9F
6 | #FF4081
7 |
8 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | latest
5 | enable
6 | nullable
7 | True
8 | false
9 |
10 |
11 |
--------------------------------------------------------------------------------
/AsyncCommandSample/Models/GitHubReleasesModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 |
4 | namespace AsyncCommandSample
5 | {
6 | record GitHubReleasesModel(long Id, Uri Url, string Tag_Name);
7 | }
8 |
9 | // C# 9.0 Workaround https://stackoverflow.com/a/62656145/5953643
10 | namespace System.Runtime.CompilerServices
11 | {
12 | [EditorBrowsable(EditorBrowsableState.Never)]
13 | public class IsExternalInit { }
14 | }
15 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "nuget"
9 | directory: "/"
10 | schedule:
11 | interval: "daily"
12 |
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Properties/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | using Foundation;
2 | using UIKit;
3 |
4 | namespace AsyncCommandSample.iOS
5 | {
6 | [Register(nameof(AppDelegate))]
7 | public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
8 | {
9 | public override bool FinishedLaunching(UIApplication app, NSDictionary options)
10 | {
11 | global::Xamarin.Forms.Forms.Init();
12 | LoadApplication(new App());
13 |
14 | return base.FinishedLaunching(app, options);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Assets/AboutAssets.txt:
--------------------------------------------------------------------------------
1 | Any raw assets you want to be deployed with your application can be placed in
2 | this directory (and child directories) and given a Build Action of "AndroidAsset".
3 |
4 | These files will be deployed with your package and will be accessible using Android's
5 | AssetManager, like this:
6 |
7 | public class ReadAsset : Activity
8 | {
9 | protected override void OnCreate (Bundle bundle)
10 | {
11 | base.OnCreate (bundle);
12 |
13 | InputStream input = Assets.Open ("my_asset.txt");
14 | }
15 | }
16 |
17 | Additionally, some Android functions will automatically load asset files:
18 |
19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
20 |
--------------------------------------------------------------------------------
/AsyncCommandSample/AsyncCommandSample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | true
6 |
7 |
8 |
9 | portable
10 | true
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Resources/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/AsyncCommandSample.UnitTests/AsyncCommandSample.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0-windows
5 | true
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | runtime; build; native; contentfiles; analyzers; buildtransitive
15 | all
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Brandon Minnick
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/brminnick/AsyncCommandSample/actions/workflows/mobile.yml)
2 |
3 | # AsyncCommandSample
4 | An iOS + Android app built in Xamarin.Forms demonstrating Xamarin.CommunityToolkit AsyncCommand
5 |
6 | ### Learn More
7 | - [Xamarin.CommunityToolkit](https://docs.microsoft.com/xamarin/community-toolkit/?WT.mc_id=mobile-15661-bramin)
8 | - [AsyncCommand](https://docs.microsoft.com/xamarin/community-toolkit/objectmodel/asynccommand?WT.mc_id=mobile-15661-bramin)
9 | - [AsyncValueCommand](https://docs.microsoft.com/xamarin/community-toolkit/objectmodel/asyncvaluecommand?WT.mc_id=mobile-15661-bramin)
10 | - [WeakEventManager](https://docs.microsoft.com/xamarin/community-toolkit/helpers/weakeventmanagert?WT.mc_id=mobile-15661-bramin)
11 | - [DelegateWeakEventManager](https://docs.microsoft.com/en-us/xamarin/community-toolkit/helpers/delegateweakeventmanager?WT.mc_id=mobile-15661-bramin)
12 |
13 | [](https://channel9.msdn.com/Shows/XamarinShow/Xamarin-Community-Toolkit-Awesome-AsyncCommand--AsyncValueCommand?WT.mc_id=mobile-15661-bramin)
14 |
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 | using Android.App;
5 |
6 | // General Information about an assembly is controlled through the following
7 | // set of attributes. Change these attribute values to modify the information
8 | // associated with an assembly.
9 | [assembly: AssemblyTitle("AsyncCommandSample.Android")]
10 | [assembly: AssemblyDescription("")]
11 | [assembly: AssemblyConfiguration("")]
12 | [assembly: AssemblyCompany("")]
13 | [assembly: AssemblyProduct("AsyncCommandSample.Android")]
14 | [assembly: AssemblyCopyright("Copyright © 2014")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 | [assembly: ComVisible(false)]
18 |
19 | // Version information for an assembly consists of the following four values:
20 | //
21 | // Major Version
22 | // Minor Version
23 | // Build Number
24 | // Revision
25 | [assembly: AssemblyVersion("1.0.0.0")]
26 | [assembly: AssemblyFileVersion("1.0.0.0")]
27 |
28 | // Add some common permissions, these can be removed if not needed
29 | [assembly: UsesPermission(Android.Manifest.Permission.Internet)]
30 | [assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
31 |
--------------------------------------------------------------------------------
/AsyncCommandSample.Android/MainActivity.cs:
--------------------------------------------------------------------------------
1 | using Android.App;
2 | using Android.Content.PM;
3 | using Android.OS;
4 | using Android.Runtime;
5 |
6 | namespace AsyncCommandSample.Droid
7 | {
8 | [Activity(Label = "AsyncCommandSample", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
9 | public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
10 | {
11 | public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
12 | {
13 | Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
14 |
15 | base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
16 | }
17 |
18 | protected override void OnCreate(Bundle savedInstanceState)
19 | {
20 | base.OnCreate(savedInstanceState);
21 |
22 | Xamarin.Essentials.Platform.Init(this, savedInstanceState);
23 | global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
24 | LoadApplication(new App());
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/AsyncCommandSample/ViewModels/BaseViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.ComponentModel;
3 | using System.Runtime.CompilerServices;
4 | using Xamarin.CommunityToolkit.Helpers;
5 |
6 | namespace AsyncCommandSample
7 | {
8 | public abstract class BaseViewModel : INotifyPropertyChanged
9 | {
10 | readonly DelegateWeakEventManager _propertyChangedEventManager = new();
11 |
12 | event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
13 | {
14 | add => _propertyChangedEventManager.AddEventHandler(value);
15 | remove => _propertyChangedEventManager.RemoveEventHandler(value);
16 | }
17 |
18 | protected void SetProperty(ref T backingStore, in T value, in System.Action? onChanged = null, [CallerMemberName] in string propertyname = "")
19 | {
20 | if (EqualityComparer.Default.Equals(backingStore, value))
21 | return;
22 |
23 | backingStore = value;
24 |
25 | onChanged?.Invoke();
26 |
27 | OnPropertyChanged(propertyname);
28 | }
29 |
30 | protected void OnPropertyChanged([CallerMemberName] in string propertyName = "") =>
31 | _propertyChangedEventManager.RaiseEvent(this, new PropertyChangedEventArgs(propertyName), nameof(INotifyPropertyChanged.PropertyChanged));
32 | }
33 | }
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIDeviceFamily
6 |
7 | 1
8 | 2
9 |
10 | UISupportedInterfaceOrientations
11 |
12 | UIInterfaceOrientationPortrait
13 | UIInterfaceOrientationLandscapeLeft
14 | UIInterfaceOrientationLandscapeRight
15 |
16 | UISupportedInterfaceOrientations~ipad
17 |
18 | UIInterfaceOrientationPortrait
19 | UIInterfaceOrientationPortraitUpsideDown
20 | UIInterfaceOrientationLandscapeLeft
21 | UIInterfaceOrientationLandscapeRight
22 |
23 | MinimumOSVersion
24 | 14.0
25 | CFBundleDisplayName
26 | AsyncCommandSample
27 | CFBundleIdentifier
28 | com.minnick.AsyncCommandSample
29 | CFBundleVersion
30 | 1.0
31 | UILaunchStoryboardName
32 | LaunchScreen
33 | CFBundleName
34 | AsyncCommandSample
35 | XSAppIconAssets
36 | Assets.xcassets/AppIcon.appiconset
37 |
38 |
39 |
--------------------------------------------------------------------------------
/.github/workflows/mobile.yml:
--------------------------------------------------------------------------------
1 | name: Xamarin
2 |
3 | on:
4 | push:
5 | branches:
6 | - "main"
7 | pull_request:
8 | branches:
9 | - "*"
10 |
11 | jobs:
12 | BuildAndroidApp:
13 | runs-on: macos-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v1
17 |
18 | - name: Setup .NET v8.0
19 | uses: actions/setup-dotnet@v1
20 | with:
21 | dotnet-version: '8.0.x'
22 |
23 | - name: Restore NuGet
24 | run: |
25 | AndroidProject=`find . -name AsyncCommandSample.Android.csproj`
26 | echo $AndroidProject
27 |
28 | XamarinFormsProject=`find . -name AsyncCommandSample.csproj`
29 | echo $XamarinFormsProject
30 |
31 | nuget restore $AndroidProject
32 | nuget restore $XamarinFormsProject
33 |
34 | - name: Build Android App
35 | run: |
36 | AndroidProject=`find . -name AsyncCommandSample.Android.csproj`
37 | echo $AndroidProject
38 |
39 | msbuild $AndroidProject /verbosity:normal /p:Configuration=Release
40 |
41 | RunUnitTests:
42 | runs-on: windows-latest
43 |
44 | steps:
45 | - uses: actions/checkout@v3
46 |
47 | - name: Setup v8.0
48 | uses: actions/setup-dotnet@v3
49 | with:
50 | dotnet-version: '8.0.x'
51 |
52 | - name: Run Unit Tests
53 | run: 'dotnet test -c Release AsyncCommandSample.UnitTests/AsyncCommandSample.UnitTests.csproj'
54 |
--------------------------------------------------------------------------------
/AsyncCommandSample.iOS/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("AsyncCommandSample.iOS")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("AsyncCommandSample.iOS")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("72bdc44f-c588-44f3-b6df-9aace7daafdd")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/AsyncCommandSample.UnitTests/Tests/XamarinCommunityToolkitInfoViewModelTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using NUnit.Framework;
4 |
5 | namespace AsyncCommandSample.UnitTests
6 | {
7 | class XamarinCommunityToolkitInfoViewModelTests
8 | {
9 | [Test]
10 | public async Task GetLatestReleaseTest()
11 | {
12 | // Arrange
13 | string? latestRelease_Initial, latestRelease_Final;
14 |
15 | var getLatestReleaseFailedTCS = new TaskCompletionSource();
16 |
17 | var xamarinCommunityToolkitInfoViewModel = new XamarinCommunityToolkitInfoViewModel(new MockPreferences());
18 | xamarinCommunityToolkitInfoViewModel.GetLatestReleaseFailed += HandleGetLatestReleaseFailed;
19 |
20 | // Act
21 | latestRelease_Initial = xamarinCommunityToolkitInfoViewModel.LatestRelease;
22 |
23 | await xamarinCommunityToolkitInfoViewModel.GetLatestRelease.ExecuteAsync().ConfigureAwait(false);
24 |
25 | latestRelease_Final = xamarinCommunityToolkitInfoViewModel.LatestRelease ?? await getLatestReleaseFailedTCS.Task.ConfigureAwait(false);
26 |
27 | // Assert
28 | Assert.Multiple(() =>
29 | {
30 | Assert.That(latestRelease_Initial, Is.Not.Null);
31 | Assert.That(latestRelease_Final, Is.Not.Null);
32 | });
33 |
34 | void HandleGetLatestReleaseFailed(object? sender, string e)
35 | {
36 | getLatestReleaseFailedTCS.SetResult(e);
37 | }
38 | }
39 |
40 | }
41 | }
--------------------------------------------------------------------------------
/AsyncCommandSample/Pages/XamarinCommunityToolkitInfoPage.cs:
--------------------------------------------------------------------------------
1 | using Xamarin.CommunityToolkit.Markup;
2 | using Xamarin.Essentials.Implementation;
3 | using Xamarin.Essentials.Interfaces;
4 | using Xamarin.Forms;
5 |
6 | namespace AsyncCommandSample
7 | {
8 | class XamarinCommunityToolkitInfoPage : ContentPage
9 | {
10 | const string _xamarinCommunityToolkitUrl = "https://github.com/xamarin/XamarinCommunityToolkit/blob/1.0.2/assets/XamarinCommunityToolkit.png?raw=true";
11 |
12 | readonly IMainThread _mainThread;
13 | readonly XamarinCommunityToolkitInfoViewModel _viewModel;
14 |
15 | public XamarinCommunityToolkitInfoPage(IMainThread mainThread)
16 | {
17 | _mainThread = mainThread;
18 |
19 | BindingContext = _viewModel = new XamarinCommunityToolkitInfoViewModel(new PreferencesImplementation());
20 | _viewModel.GetLatestReleaseFailed += HandleGetLatestReleaseFailed;
21 |
22 | Content = new StackLayout
23 | {
24 | Children =
25 | {
26 | new Image { Source = _xamarinCommunityToolkitUrl, HeightRequest = 250 }.Center(),
27 |
28 | new Label().Center().TextCenter()
29 | .Bind