Skip to content

Commit

Permalink
BREAKING: Changed namespace to CurrentDevice from BlazorCurrentDevice
Browse files Browse the repository at this point in the history
CHANGED: Dictionary to not use ``Add``, but instead ``TryAdd`` to not show errors.
ADDED: Separate ReadMe for Nuget
ADDED: Nuget Tags to be found easier
  • Loading branch information
HugoVG committed Apr 20, 2024
1 parent f1510a1 commit 6a48e10
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 157 deletions.
5 changes: 2 additions & 3 deletions BlazorCurrentDevice-Server/Components/Pages/Home.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@page "/"
@using BlazorCurrentDevice
@inject IJSRuntime JSRuntime
@using CurrentDevice
@inject ICurrentDeviceService CurrentDeviceService
@rendermode InteractiveServer

Expand Down Expand Up @@ -108,9 +107,9 @@
{
// Get the user agent using JavaScript interop
UserAgent = await CurrentDeviceService.GetUserAgent();
Android = await CurrentDeviceService.Android();
AndroidPhone = await CurrentDeviceService.AndroidPhone();
AndroidTablet = await CurrentDeviceService.AndroidTablet();
Android = await CurrentDeviceService.Android();
Blackberry = await CurrentDeviceService.Blackberry();
BlackberryPhone = await CurrentDeviceService.BlackberryPhone();
BlackberryTablet = await CurrentDeviceService.BlackberryTablet();
Expand Down
2 changes: 1 addition & 1 deletion BlazorCurrentDevice-Server/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using BlazorCurrentDevice;
using CurrentDevice;
using BlazorCurrentDevice_Server.Components;

var builder = WebApplication.CreateBuilder(args);
Expand Down
2 changes: 1 addition & 1 deletion BlazorCurrentDevice-Wasm/Pages/Home.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@page "/"
@using BlazorCurrentDevice
@using CurrentDevice
@inject ICurrentDeviceService CurrentDeviceService

<h1 class="colour-text big-text">Blazor Current Device Demo</h1>
Expand Down
2 changes: 1 addition & 1 deletion BlazorCurrentDevice-Wasm/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using BlazorCurrentDevice;
using CurrentDevice;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using BlazorCurrentDevice_Wasm;
Expand Down
12 changes: 7 additions & 5 deletions CurrentDevice/CurrentDevice.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
<PackageProjectUrl>https://github.com/hugovg/CurrentDevice</PackageProjectUrl>
<RepositoryUrl>https://github.com/hugovg/CurrentDevice</RepositoryUrl>
<RepositoryType>C#</RepositoryType>
<PackageReleaseNotes>Update to make Blazor Server/Hybrid work, Standard 2.1 net8.0</PackageReleaseNotes>
<PackageReleaseNotes>Breaking change: Namespace name changed, internal dictionary should longer cause exceptions</PackageReleaseNotes>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
<Authors>HugoVG</Authors>
<Copyright>HugoVG</Copyright>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RootNamespace>BlazorCurrentDevice</RootNamespace>
<RootNamespace>CurrentDevice</RootNamespace>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<PackageTags>Blazor;CurrentDevice;WASM;Blazor Server;UserAgent;Web</PackageTags>
<PackageId>CurrentDevice</PackageId>
</PropertyGroup>


Expand All @@ -23,9 +25,9 @@
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="3.1.3" />
</ItemGroup>
<ItemGroup>
<None Include="../README.md" Pack="true" PackagePath="README.md" />
<None Include="../README.md" />
<None Include="../LICENSE.txt" Pack="true" PackagePath="LICENSE.txt" />

<None Include="../NugetReadMe.md" Pack="true" PackagePath="README.md" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
Expand Down
150 changes: 37 additions & 113 deletions CurrentDevice/CurrentDeviceService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,144 +2,71 @@
using Microsoft.JSInterop;
using System.Threading.Tasks;

namespace BlazorCurrentDevice
namespace CurrentDevice
{
internal class CurrentDeviceService : ICurrentDeviceService
{
private IJSRuntime JsRuntime { get; set; }

public CurrentDeviceService(IJSRuntime jSRuntime)
{
JsRuntime = jSRuntime;
}
public CurrentDeviceService(IJSRuntime jSRuntime) => JsRuntime = jSRuntime;

private Dictionary<string, bool> _deviceCache = new Dictionary<string, bool>();
private readonly Dictionary<string, bool> _deviceCache = new Dictionary<string, bool>();


public async Task<bool> MacOs()
{
return await Find("mac");
}
public async Task<bool> MacOs() => await Find("mac");

public async Task<string> Type()
{
return await Desktop() ? "desktop" :
await Tablet() ? "tablet" :
await Mobile() ? "mobile" :
await Television() ? "television" : "unknown";
}
public async Task<string> Type() =>
await Desktop() ? "desktop" :
await Tablet() ? "tablet" :
await Mobile() ? "mobile" :
await Television() ? "television" : "unknown";

public Task<bool> Windows()
{
return Find("windows");
}
public Task<bool> Windows() => Find("windows");

public async Task<bool> WindowsPhone()
{
return await Windows() && await Find("phone");
}
public async Task<bool> WindowsPhone() => await Windows() && await Find("phone");

public async Task<bool> WindowsTablet()
{
return await Windows() && await Find("touch") && !await WindowsPhone();
}
public async Task<bool> WindowsTablet() => await Windows() && await Find("touch") && !await WindowsPhone();

public Task<bool> iPhone()
{
return Find("iphone");
}
public Task<bool> iPhone() => Find("iphone");

public Task<bool> iPod()
{
return Find("ipod");
}
public Task<bool> iPod() => Find("ipod");

public Task<bool> iPad()
{
return Find("ipad");
}
public Task<bool> iPad() => Find("ipad");

public async Task<bool> Desktop()
{
return (!await Mobile()) && (!await Tablet()) && (!await Television());
}
public async Task<bool> Desktop() => !await Mobile() && !await Tablet() && (!await Television());

public async Task<bool> iOS()
{
return await iPhone() || await iPod() || await iPad();
}

public async Task<bool> Android()
{
return await Find("android");
}
public async Task<bool> iOS() => await iPhone() || await iPod() || await iPad();

public async Task<bool> AndroidPhone()
{
return await Android() && await Find("mobile");
}
public async Task<bool> Android() => await Find("android");

public async Task<bool> AndroidTablet()
{
return await Android() && !await AndroidPhone();
}
public async Task<bool> AndroidPhone() => await Android() && await Find("mobile");

public async Task<bool> Blackberry()
{
return await Find("blackberry") || await Find("bb10") || await Find("rim");
}
public async Task<bool> AndroidTablet() => await Android() && !await AndroidPhone();

public async Task<bool> BlackberryPhone()
{
return await Blackberry() && !(await Find("tablet"));
}
public async Task<bool> Blackberry() => await Find("blackberry") || await Find("bb10") || await Find("rim");

public async Task<bool> BlackberryPhone() => await Blackberry() && !(await Find("tablet"));

public async Task<bool> BlackberryTablet()
{
return await Blackberry() && await Find("tablet");
}
public async Task<bool> BlackberryTablet() => await Blackberry() && await Find("tablet");

public Task<bool> MeeGo()
{
return Find("meego");
}
public Task<bool> MeeGo() => Find("meego");

public async Task<bool> Mobile()
{
return await AndroidPhone() || await iPhone() || await iPod() || await WindowsPhone() ||
await BlackberryPhone() || await MeeGo();
}
public async Task<bool> Mobile() =>
await AndroidPhone() || await iPhone() || await iPod() || await WindowsPhone() ||
await BlackberryPhone() || await MeeGo();

public async Task<bool> Tablet()
{
return await iPad() || await AndroidTablet() || await BlackberryTablet() || await WindowsTablet();
}
public async Task<bool> Tablet() => await iPad() || await AndroidTablet() || await BlackberryTablet() || await WindowsTablet();

public async Task<bool> Television()
{
return FindIn(UserAgent ??= await GetUserAgent(), Televisions) != "unknown";
}
public async Task<bool> Television() => FindIn(UserAgent ??= await GetUserAgent(), Televisions) != "unknown";


public async Task<bool> Landscape()
{
return await Orientation() == "landscape";
}
public async Task<bool> Landscape() => await Orientation() == "landscape";

public async Task<bool> Portrait()
{
return await Orientation() == "portrait";
}
public async Task<bool> Portrait() => await Orientation() == "portrait";

public async Task<string> Orientation()
{
return FindIn(await GetOrientation(), Orientations);
}
public async Task<string> Orientation() => FindIn(await GetOrientation(), Orientations);

public async Task<string> OS()
{
return FindIn(UserAgent ??= await GetUserAgent(), OperatingSystems);
}
public async Task<string> OS() => FindIn(UserAgent ??= await GetUserAgent(), OperatingSystems);


private async Task<bool> Find(string value)
Expand All @@ -151,11 +78,11 @@ private async Task<bool> Find(string value)

UserAgent ??= await GetUserAgent();
foundValue = UserAgent.Contains(value);
_deviceCache.Add(value, foundValue);
_deviceCache.TryAdd(value, foundValue);
return foundValue;
}

private string FindIn(string searchString, string[] values)
private static string FindIn(string searchString, string[] values)
{
foreach (var value in values)
{
Expand All @@ -168,10 +95,7 @@ private string FindIn(string searchString, string[] values)
return "unknown";
}

public async Task<string> GetUserAgent()
{
return (await JsRuntime.InvokeAsync<string>("eval", "window.navigator.userAgent")).ToLower();
}
public async Task<string> GetUserAgent() => (await JsRuntime.InvokeAsync<string>("eval", "window.navigator.userAgent")).ToLower();

/// <summary>
/// We are using either Scoped or Singleton so this method will be called only once for wasm, and once per connection for server
Expand Down
2 changes: 1 addition & 1 deletion CurrentDevice/ICurrentDeviceService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Threading.Tasks;

namespace BlazorCurrentDevice
namespace CurrentDevice
{
/// <summary>
/// Service to get information about the current device
Expand Down
2 changes: 1 addition & 1 deletion CurrentDevice/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.Extensions.DependencyInjection;

namespace BlazorCurrentDevice
namespace CurrentDevice
{
public static class ServiceCollectionExtensions
{
Expand Down
88 changes: 88 additions & 0 deletions NugetReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# CurrentDevice

Device/User agent detector made in Blazor for Blazor. This library is a port of [CurrentDevice](https://github.com/matthewhudson/current-device/)

No need to use JavaScript interop to detect the device or user agent. This library is a pure C# implementation of the original library.

This library is trimmable and does not rely on Javascript (no need to add a <script> tag somewhere)

### Nuget CLI
``dotnet add package CurrentDevice``

### Csproj
``<PackageReference Include="CurrentDevice" Version="1.0.2" />``

## Add reference in _Imports.razor

`@using CurrentDevice`

## Usage

### Add the service in your services method

```csharp
var builder = WebAssemblyHostBuilder.CreateDefault(args);
//... Shortend for brevity
builder.Services.AddCurrentDeviceService();
//... Shortend for brevity
await builder.Build().RunAsync();
```

### Inject the service in your component

```csharp
@code{
[Inject] ICurrentDeviceService CurrentDeviceService { get; set; }
}
```
or
```csharp
@inject ICurrentDeviceService CurrentDeviceService
```

### Usage in your component

#### Blazor WASM

```csharp
protected override async Task OnInitializedAsync()
{
UserAgent = await CurrentDeviceService.GetUserAgent();
}
```

#### Blazor Server

```csharp
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
UserAgent = await CurrentDeviceService.GetUserAgent();
StateHasChanged();
}
}
```



#### Device Methods

To see a real world example you can visit the example [here on Github](https://hugovg.github.io/CurrentDevice/)



## Technical information

### Lifetimes

Eventhough in DI it get added as scoped,
blazor WASM will treat it as a singleton [more on that here](https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/dependency-injection?view=aspnetcore-8.0#service-lifetime)
meaning that if an user changes User agents and refreshes the page it'll still display old data untill a page refresh

For blazor server it is scoped and every page request will have up to date information, interal responses get cached clientside per request so that if you check for Ipad then iOs it'll save some requests to the browser



## License
MIT
Loading

0 comments on commit 6a48e10

Please sign in to comment.