フォックスのようなテーマを切り替える🦊 環境光に基づきます💡 あなたの角度アプリで
DISCLAIMER: This is a continuation of this article where I write about implementing a theme switch in an Angular App. If you haven't already read that, I recommend you to read this first.👇🏻
テーマスイッチを実装しましょう🎨 角材サイトのように
シドドラースアジャメラ🇮🇳 角度・ Mar 19 ' 20・ 11分読む
That way you'll have more context of where I'm coming from.🙂
This article is intended for an audience with mixed experience levels. I've still added a TL;DR; below 👇🏻 as a precautionary measure, in case you're just interested in a specific section.
TLドクター
Enter: the
AmbientLightSensor
Web Interface 📡 AmbientLightSensor
Web Interface 暗闇の中でなぜ暗いテーマ?🤷🏻♂️
So, as I mentioned in the , Dark Mode is awesome and low-lit ambiances are the best suited for #DarkMode.
Now changing themes in our App based on user interaction is OK. But we can take it to the next level by intelligently switching themes, based on the ambient lighting conditions that the user is in.
And that's exactly what we're going to do in this article.
それが暗いとき⚡
Now you might think, how exactly do we determine that it's dark. Well, there's something called Illuminance that can help us do that.
Illuminance is a measure of the luminous flux spread over a given area.
One can think of luminous flux (which is measured in lumens BTW) as a measure of the total "amount" of visible light present, and the illuminance as a measure of the intensity of illumination on a surface.
「簡単に言えば、光束は闇に反比例している」
若干の参考のために、我々は暗闇を決定するために、このテーブルを使います:
< div >
上記の表から判断すると、光束が10以下であれば暗い環境にあると考えるのは安全でしょう.しかし、それは私が選んだ数です.あなたの好みに基づいて10 - 20(またはあなたが好きなら50)の間の番号を選択してください.p >
したがって、我々は、環境が明るいフラックスに基づいて明暗であるかどうか決定することができます.しかし、どのように我々は光束を決定するのですか?🤔
< P >
< H >
を入力します
AmbientLightSensor
Webインタフェース📡
This is a cool new interface from the Sensor APIs that returns the current light level or illuminance of the ambient light around the hosting device.
The
AmbientLightSensor
object has a property namedilluminance
on it, that returns the current light level in lux of the ambient light level around the hosting device.
It would only work on devices that have the ambient light sensor(hardware) on them(obviously). With the help of this AmbientLightSensor
interface, our browsers can access the data collected by Ambient Light Sensors on devices. Cool, isn't it? 🤩
What does that mean for us? Well, you can think of
illuminance
as the luminous flux incident on a surface.
Now we know how to get the illuminance
, and from the Illuminance Table 我々は、我々がいる環境が暗いか軽いかどうか決定することができますp >
だから、もし環境が暗いならilluminance
< ;==10(また、この数は全くあなた次第です)、そうでなければ明かりですp >
<利用>AmbientLightSensor
アクセスインタフェースilluminance
は非常に簡単ですし、使用方法はthis example MDNドキュメントp >
しかし、このインターフェースを使用している間、面倒を見る必要があります.一つずつやりましょうp >
< H 3 >
特徴検出🕵🏻♂️:
if ("AmbientLightSensor" in window) {
// Yay! The Browser has what it takes
}
取り扱いエッジケース
Checking whether the browser supports a feature doesn't guarantee that everything will work as expected. There might be errors:
- While instantiation the sensor.
- While using it.
- When the user's permissions might be required to use the sensor.
- When the sensor type might not be supported by the device.
So all these scenarios would result in an error. So while using this interface, we'll have to cater to all these edge cases as well.
Now that we know what we're looking at, let's try to implement this in our App.
使用ウェブサイトインタフェース
Reading the illuminance
and handling all these edge cases is the major task that we should delegate to a service. So let's implement a service in Angular that will handle all these things for us.
The only output that we're going to expect from this service is an Observable that either gives us the illuminance
or an error message that we could show to the user. So let's do this. I'll name this service AmbientLightSensorService
.
Also, since this service would also rely on the window
object, let's provide it as a value so that we could then inject it as a dependency in our AmbientLightSensorService
.
So in our AppModule
:
アプリ。モジュールです。TS高橋潤子>クラスをハイライト表示する... "/環境光センサー"サービスからインポートします ngmodule () ... プロバイダ アンビエンスライトサービス { } ウィンドウを提供する。 USEVALUE :ウィンドウ // ... ] ))> クラスの追加モジュール < div >また、メッセージ、エラータイプ、センサーポリシー、センサー名などもたくさんあります.では、定数を定数として公開しましょう.
普通。コンストTS
クラスをハイライト表示する
export const SENSOR_NAME = "AmbientLightSensor";
export const SENSOR_POLICY_NAME = "ambient-light-sensor";
export const ACCESS_DENIED = "denied";
export const THEME_OPTIONS_URL = "/assets/options.json";
export const THEME_BASE_PATH = "node_modules/@angular/material/prebuilt-themes";
export const STYLE_TO_SET = "theme";
export const DARK_THEME = "pink-bluegrey";
export const LIGHT_THEME = "deeppurple-amber";
export const ERROR_TYPES = {
SECURITY: "SecurityError",
REFERENCE: "ReferenceError",
NOT_ALLOWED: "NotAllowedError",
NOT_READABLE: "NotReadableError"
};
export const ERROR_MESSAGES = {
UNSUPPORTED_FEATURE: "Your browser doesn't support this feature",
BLOCKED_BY_FEATURE_POLICY:
"Sensor construction was blocked by a feature policy.",
NOT_SUPPORTED_BY_USER_AGENT: "Sensor is not supported by the User-Agent.",
PREMISSION_DENIED: "Permission to use the ambient light sensor is denied.",
CANNOT_CONNECT: "Cannot connect to the sensor."
};
< div >うまくいけば、私はこれらの変数を自分が説明しているように命名しました.p >
<堀田>
環境光センササービスTS
クラスをハイライト表示する
import { ReplaySubject, Observable } from "rxjs";
import { Injectable } from "@angular/core";
import {
SENSOR_NAME,
SENSOR_POLICY_NAME,
ACCESS_DENIED,
ERROR_TYPES,
ERROR_MESSAGES
} from "./common.const";
@Injectable()
export class AmbientLightSensorService {
private illuminance: ReplaySubject <number> = new ReplaySubject <number>(1);
illuminance$: Observable<number> = this.illuminance.asObservable();
constructor(private window: Window) {
try {
if (SENSOR_NAME in window) {
this.startReading();
} else {
this.illuminance.error(ERROR_MESSAGES.UNSUPPORTED_FEATURE);
}
} catch (error) {
// Handle construction errors.
if (error.name === ERROR_TYPES.SECURITY) {
this.illuminance.error(ERROR_MESSAGES.BLOCKED_BY_FEATURE_POLICY);
} else if (error.name === ERROR_TYPES.REFERENCE) {
this.illuminance.error(ERROR_MESSAGES.NOT_SUPPORTED_BY_USER_AGENT);
} else {
this.illuminance.error(`${error.name}: ${error.message}`);
}
}
}
private startReading() {
const sensor = new AmbientLightSensor();
sensor.onreading = () => this.illuminance.next(sensor.illuminance);
sensor.onerror = async event => {
// Handle runtime errors.
if (event.error.name === ERROR_TYPES.NOT_ALLOWED) {
// Branch to code for requesting permission.
const result = await navigator.permissions.query({
name: SENSOR_POLICY_NAME
});
if (result.state === ACCESS_DENIED) {
this.illuminance.error(ERROR_MESSAGES.PREMISSION_DENIED);
return;
}
this.startReading();
} else if (event.error.name === ERROR_TYPES.NOT_READABLE) {
this.illuminance.error(ERROR_MESSAGES.CANNOT_CONNECT);
}
};
sensor.start();
}
}
< div >実装は前のセクションで議論したすべてのエッジケースに対応します.p >
基本的に、私たちは
illuminance
ReplaySubject<number>
としてilluminance$
Observable<number>
.<なぜ>
ReplaySubject<number>(1)
?私たちは初期値を持っていないので、使用する代わりにそれを使うほうがより意味があるでしょうBehaviorSubject<number>(null)
.今、私たちは新しいルクス値を
illuminance
ReplaySubject
を呼び出すことによってnext
方法.エラーの場合は、error
メソッドp >また、メソッド名とエラーメッセージ名はかなり自己説明的です.もし何かがまだはっきりしていないなら、下にコメントしてください.p >
そして、現在サービスが準備ができているので、我々はこのサービスを我々の依存性として注入することができます
HeaderComponent
とレバレッジilluminance$
Observable
ルクス値(あるいはエラーメッセージ)へのアクセスを得るにはp >ヘッダ.コンポーネント.TS
クラスをハイライト表示する
import { Component, OnDestroy, OnInit } from "@angular/core";
import { MatSnackBar } from "@angular/material/snack-bar";
import { Observable, Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { AmbientLightSensorService } from "../ambient-light-sensor.service";
import { DARK_THEME, LIGHT_THEME } from "../common.const";
import { Option } from "../option.model";
import { ThemeService } from "../theme.service";
@Component({
selector: "app-header",
templateUrl: "./header.component.html",
styleUrls: ["./header.component.css"]
})
export class HeaderComponent implements OnInit, OnDestroy {
options$: Observable<Array<Option>> = this.themeService.getThemeOptions();
private unsubscribe$ = new Subject<void>();
constructor(
private readonly themeService: ThemeService,
private readonly alsService: AmbientLightSensorService,
private readonly snackBar: MatSnackBar
) {}
ngOnInit() {
this.themeService.setTheme(DARK_THEME);
this.alsService.illuminance$
.pipe(takeUntil(this.unsubscribe$))
.subscribe(
illuminance => {
illuminance <= 10
? this.themeService.setTheme(DARK_THEME)
: this.themeService.setTheme(LIGHT_THEME);
},
error => this.showMessage(error)
);
}
themeChangeHandler(themeToSet) {
this.themeService.setTheme(themeToSet);
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
private showMessage(messageToShow) {
this.snackBar.open(messageToShow, "OK", {
duration: 4000
});
}
}
< div >あなたが気付くように:
<ウル>
AmbientLightSensorService
依存関係として.ngOnInit
ライフサイクル・フックsubscribe
へのINGObservable
. ここから<ウル>
illuminance
値.ここでチェックilluminance
値<ウル>
<= 10
, それから、我々はDARK_THEME
. > 10
, それから、我々はLIGHT_THEME
. error
メッセージ.そこから、我々は単にshowMessage
スナックバーを表示する方法です.< ull >
私たちもそうです
subscribe
へのINGObservable
今回は、どんなメモリリークも避けるために、明示的に何かをしなければなりません.それをするために、私たちはtakeUntil
演算子p >Read more about this approach in this article on AngularInDepth by Tomas Trajan
そして、それはそれです.我々
AmbientLightSensor
テーマスイッチが準備完了です.テストしましょうp >< H >
試してみる🧪
Before we do that, there's a caveat. And it has something to do with browser support.
< source >
<<>
<> P >
上で見ることができるように、ブラウザのサポートは、現時点では素晴らしいことではありません.しかし、我々は少なくとも世界で最も良いブラウザー(Ahem Chrome Ahem)でこれをテストしますp >
そのためには、まずフラグを有効にしなければなりません.
だから私は行きますchrome://flags/#enable-generic-sensor-extra-classes
と私の携帯電話でそれを有効にする(私のラップトップは、それに周囲の光センサーを持っていない).それから、電話でブラウザを再起動します.p >
<小野寺>
<高橋>https://www.youtube.com/embed/CEQTOn1OILo"allowfulscreen = ""読み込み= "lazy "
< iframe >
<> P >
< P >
そして最後のコードは< p >です.
< p >< iframe src ="https://stackblitz.com/edit/ambient-light-sensor-theme-switch?embed=1&アンプ"width ="100 % "height ="500 "スクロール("no "フレームワーク= "no "allowfulscreen = =""allow透明= = "true "読み込み= "lazy "
< iframe >
<> P >
< H >
次の手順👣
As of now, there's a slight issue in the App. What if the user doesn't want to change the theme automagically, based on the lighting conditions? We can add in a simple fix as a settings/preference menu asking to turn this behavior ON/OFF and switch the theme only when the behavior is turned ON.
Give it a try and implement the Preference/Settings Menu and then only switch the theme if the user has switched this auto-theme-switch behavior on.
クロージングノート🎉
Awwww! You're still here? Thanks for sticking around. I hope you liked it.
I’m extremely grateful to , and for taking the time to proofread it and providing all the constructive feedback in making this article better.
I hope this article has taught you something new related to Angular and Web in general. If it did, hit that 🧡/🦄 icon, and add it to your reading list(🔖). Also, share this article with your friends who are new to Angular/Web and want to achieve something similar.
Please stay tuned while I work on uploading a video version of this article. 📺
Icon Courtesy: Angular Material AngularioプレスキットCSS 名詞プロジェクトからのMonkikによってLight sensor 名詞プロジェクトからのAdnen Kadriによって
次に次まで.👋🏻
Reference
この問題について(フォックスのようなテーマを切り替える🦊 環境光に基づきます💡 あなたの角度アプリで), 我々は、より多くの情報をここで見つけました https://dev.to/angular/switch-themes-like-a-fox-based-on-ambient-light-in-your-angular-apps-nk9テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol