All authors

Claude Skills by HoangNguyen0403
github.com/HoangNguyen04031,434 skills30 installs1,975 views
- Android Navigation Type SafeUse Navigation Compose 2.8.0 or newer with Kotlin serialization-backed route types. Define each destination as a serializable object or data class, then register the destination with the typed `composable<T>` API: ```kotlin import androidx.compose.runtime.Composable import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute impo...Votes: 0GitHub stars: 549
- Android Navigation Type SafeRepresent the detail destination as a serializable data class whose argument is a `Long`: ```kotlin @Serializable sealed interface ProductScreen { @Serializable data object List : ProductScreen @Serializable data class Detail(val productId: Long) : ProductScreen } ``` Register and navigate to it using the typed APIs: ```kotlin NavHost( navController = navController, startDestination = ProductScreen.List, ) { composable<ProductScreen.List> { ProductListScreen( onProductClick = { productId -> n...Votes: 0GitHub stars: 549
- Android Navigation Type SafePassing a `NavController` directly into child composables is not the recommended structure. Keep the controller in the `NavHost` or navigation-graph layer and hoist navigation events into screen-level callbacks. This keeps screens independent of the navigation implementation and makes them easier to test and reuse. ```kotlin composable<ProductScreen.List> { ProductListScreen( onProductClick = { productId -> navController.navigate(ProductScreen.Detail(productId)) }, onOpenSettings = { navContr...Votes: 0GitHub stars: 549
- Android NavigationUse `androidx.navigation:navigation-compose` and keep the route contract in a sealed type. The list UI should emit a product ID callback; it should not receive a `NavController` directly. ```kotlin sealed class Screen { abstract val route: String data object ProductList : Screen() { override val route = "products" } data class ProductDetail(val productId: Long) : Screen() { override val route: String get() = "product/$productId" companion object { const val pattern = "product/{productId}" con...Votes: 0GitHub stars: 549
- Android NavigationHandle a web App Link in two places: the Android manifest makes the activity a candidate for the incoming URL, and the Compose `NavHost` maps that URL to a typed destination. The app needs the `androidx.navigation:navigation-compose` dependency. Define the destination pattern centrally and validate the argument before loading content: ```kotlin sealed class Screen { data object ProductList : Screen() { val route = "products" } data object ProductDetail : Screen() { const val route = "product/...Votes: 0GitHub stars: 549
- Android NavigationIt may work mechanically, but it is not a good navigation contract. A raw interpolated route such as `"product/$id"` spreads route syntax through the UI, makes argument handling easy to get wrong, and conflicts with the project’s sealed-route rule. Define the pattern and route construction together in a sealed type, then use that type at both call sites: ```kotlin sealed class Screen { data object ProductList : Screen() { val route = "products" } data class ProductDetail(val productId: Long) ...Votes: 0GitHub stars: 549
- Android NetworkingUse Retrofit 2 on top of OkHttp 4. Put authentication in an OkHttp interceptor, configure Kotlinx Serialization explicitly as the JSON converter, and keep HTTP/error interpretation in a repository rather than in the API interface. ```kotlin // Dependencies (use versions compatible with the project) implementation("com.squareup.retrofit2:retrofit:<version>") implementation("com.squareup.okhttp3:okhttp:<version>") implementation("com.squareup.okhttp3:logging-interceptor:<version>") implementati...Votes: 0GitHub stars: 549
- Android NetworkingUse Kotlinx Serialization with Retrofit. It is type-safe, works with Kotlin `@Serializable` models, and is the serialization standard for this Android networking setup. Configure its converter explicitly with the JSON media type; do not rely on an unspecified or raw converter factory. Add the Kotlin serialization plugin and the JSON/converter dependencies using versions compatible with the project: ```kotlin plugins { kotlin("plugin.serialization") version "<kotlin-version>" } dependencies { ...Votes: 0GitHub stars: 549
- Android NetworkingFor this networking standard, no: every Retrofit API call must be a `suspend` function. A non-suspend method such as `Call<UserDto>` or a direct `execute()` call permits a blocking or inconsistent calling pattern and violates the rule that API calls are coroutine-friendly and non-blocking. Declare only the endpoint in the API interface: ```kotlin interface UserApi { @GET("users/{id}") suspend fun getUser(@Path("id") id: String): UserDto } ``` Then invoke it from a coroutine, for example `view...Votes: 0GitHub stars: 549
- Android NotificationsOn Android 8.0 (API 26) and later, every notification must be posted to an existing `NotificationChannel`. If the channel ID passed to `NotificationCompat.Builder` does not exist, the notification can be silently dropped. Create the channel before posting notifications, typically from `Application.onCreate()` or before the first notification: ```kotlin private const val NOTIFICATION_CHANNEL_ID = "default" fun createNotificationChannel(context: Context) { if (Build.VERSION.SDK_INT >= Build.VER...Votes: 0GitHub stars: 549
- Android NotificationsUse Firebase Cloud Messaging (FCM) with a `FirebaseMessagingService`, a notification channel, and a `PendingIntent` for taps. First add Firebase Messaging using the Firebase BoM: ```groovy dependencies { implementation platform('com.google.firebase:firebase-bom:32.7.0') implementation 'com.google.firebase:firebase-messaging-ktx' } ``` Declare the service in `AndroidManifest.xml`: ```xml <service android:name=".MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action andro...Votes: 0GitHub stars: 549
- Android NotificationsNo. On Android 13 (API 33) and later, request `POST_NOTIFICATIONS` at a contextually useful point after explaining why notifications help. Do not show the system prompt unconditionally on the first app launch; a short priming dialog improves the user's understanding and avoids an unexpected permission request. Declare the permission: ```xml <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> ``` Register a launcher in an activity and guard it by API level and current perm...Votes: 0GitHub stars: 549
- Android PerformanceMeasure the 3 seconds first, then optimize the work on the critical startup path. Use a release/profileable build and a cold-start benchmark or system trace to distinguish process startup, first frame, and work that happens immediately after the first frame. 1. Audit `Application.onCreate` and all initialization it triggers. Remove network calls, synchronous disk/database work, migrations, reflection-heavy setup, and construction of SDKs that are not required to show the first screen. Require...Votes: 0GitHub stars: 549
- Android PerformanceDiagnose the jank on a profileable/release-like build while reproducing the same scroll. First determine whether frames are missing because of Compose recomposition, layout/measure work, image decoding, or another main-thread task. Use Layout Inspector to find unnecessary recompositions and inspect the system trace or Android Studio profiler for long work during scroll. JankStats is useful for recording frame metrics and identifying the screens or interactions that drop below the intended fra...Votes: 0GitHub stars: 549
- Android PerformanceThe main issue is usually decoding the full network image into a `Bitmap`. Compressed network size is not the memory cost of the decoded bitmap; an ARGB image needs approximately `width × height × 4` bytes. Load a thumbnail at the size the `ImageView` actually displays, and let the image library cache the result. For example, with Glide, use a known pixel size for the target rather than the original URL dimensions: ```kotlin Glide.with(holder.imageView) .load(item.thumbnailUrl) .override(targ...Votes: 0GitHub stars: 549
- Android PersistenceReturn a `Flow` from the DAO query. Room tracks the tables referenced by the query and re-runs it when those tables are invalidated, so callers receive the initial rows and later updates without manually refreshing. ```kotlin @Entity(tableName = "products") data class ProductEntity( @PrimaryKey val id: String, val name: String, val priceCents: Long, ) @Dao interface ProductDao { @Query("SELECT * FROM products ORDER BY name") fun observeProducts(): Flow<List<ProductEntity>> @Insert(onConflict ...Votes: 0GitHub stars: 549
- Android PersistencePrefer DataStore for new settings. `SharedPreferences` is synchronous, weakly typed, and does not provide a reactive `Flow` API; it can also encourage disk work from application code on the main thread. DataStore provides asynchronous reads, observable updates, and atomic edits. Choose the DataStore variant based on the settings contract: - Use `PreferencesDataStore` for a small set of simple, dynamically keyed primitives. - Use `ProtoDataStore` when settings have a stable schema and type saf...Votes: 0GitHub stars: 549
- Android PersistenceTechnically a ViewModel can receive a `@Entity`, but it should not make the entity part of the UI contract. Keep Room entities simple and map them to domain or UI models in the repository. This prevents database column names, annotations, persistence-only fields, and schema changes from leaking into the ViewModel and composables/views. ```kotlin @Entity(tableName = "products") data class ProductEntity( @PrimaryKey val id: String, val name: String, val priceCents: Long, ) data class Product( v...Votes: 0GitHub stars: 549
- Android ResourcesUse a plural resource instead of hardcoding the sentence: ```xml <!-- res/values/strings.xml --> <plurals name="cart_items"> <item quantity="one">You have 1 item in your cart</item> <item quantity="other">You have %d items in your cart</item> </plurals> ``` In Jetpack Compose: ```kotlin Text(stringResource(R.plurals.cart_items, itemCount, itemCount)) ``` For non-Compose code: ```kotlin resources.getQuantityString(R.plurals.cart_items, itemCount, itemCount) ``` Keep all UI text in `strings.xml...Votes: 0GitHub stars: 549
- Android ResourcesDefine the message in `res/values/strings.xml` using a `%s` format argument: ```xml <string name="hello_user">Hello %s!</string> ``` In Jetpack Compose: ```kotlin Text(stringResource(R.string.hello_user, userName)) ``` For non-Compose UI code: ```kotlin context.getString(R.string.hello_user, userName) ``` This avoids UI string concatenation and keeps the message localizable.Votes: 0GitHub stars: 549
- Android ResourcesPrefer XML `VectorDrawable` icons for most Android app icons: - Scale cleanly across mdpi, hdpi, xhdpi, and xxhdpi. - Usually reduce APK size. - Are easy to tint and theme. - Work well with Compose and Views. Use PNG only for raster artwork—such as photos, textures, or highly detailed illustrations—or when an existing asset cannot be converted cleanly to a vector. Place density-specific PNGs in `drawable-mdpi`, `drawable-hdpi`, etc. Example: ```xml <!-- res/drawable/ic_search.xml --> <vector ...Votes: 0GitHub stars: 549
- Android SecurityRegular `SharedPreferences` is not appropriate for an auth token. It is app-private in normal operation, but it is not encrypted at rest; a compromised, rooted, debug, or backup-related environment may expose its contents. Do not put the token in source code or log it. Store the token with `EncryptedSharedPreferences`, backed by an Android Keystore-protected `MasterKey`: ```kotlin val masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() val securePrefs...Votes: 0GitHub stars: 549
- Android SecurityDisable cleartext traffic in the app's network security configuration, then reference that configuration from the manifest. `res/xml/network_security_config.xml`: ```xml <?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="false" /> </network-security-config> ``` `AndroidManifest.xml`: ```xml <application android:networkSecurityConfig="@xml/network_security_config" ...> </application> ``` Also make every client URL use `https://`, avoid raw ...Votes: 0GitHub stars: 549
- Android SecurityMake the receiver's trust boundary explicit: ```xml <receiver android:name=".InternalReceiver" android:exported="false" /> ``` Use `android:exported="false"` when the receiver is only for broadcasts from your own app. If it has an `intent-filter`, Android 12+ requires an explicit exported value, so do not leave the attribute implicit. Set `android:exported="true"` only when external apps or the system must invoke it. In that case, restrict access with the narrowest appropriate permission (pre...Votes: 0GitHub stars: 549
- Android StateNo. The `ViewModel` should own all state mutations; exposing a public `MutableStateFlow` allows the UI (or any consumer) to bypass that ownership and write invalid state directly. Keep the mutable flow private and expose exactly one read-only flow: ```kotlin private val _uiState = MutableStateFlow<UiState>(UiState.Loading) val uiState: StateFlow<UiState> = _uiState.asStateFlow() ``` The UI should send intent-style calls such as `viewModel.retry()` or `viewModel.onQueryChanged(query)`. The `Vi...Votes: 0GitHub stars: 549
- Android StateModel the screen as one sealed `UiState` using the loading/content/error (LCE) variants. Make state data immutable so Compose can reason about it reliably: ```kotlin @Immutable sealed interface FeedUiState { data object Loading : FeedUiState @Immutable data class Content(val items: ImmutableList<Post>) : FeedUiState @Immutable data class Error(val message: String?) : FeedUiState } class FeedViewModel( private val getFeed: GetFeedUseCase, ) : ViewModel() { private val _uiState = MutableStateFl...Votes: 0GitHub stars: 549
- Android StateCollect the `ViewModel`'s single `StateFlow<UiState>` with the lifecycle-aware Compose API: ```kotlin @Composable fun FeedRoute(viewModel: FeedViewModel = hiltViewModel()) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() when (val state = uiState) { FeedUiState.Loading -> LoadingContent() is FeedUiState.Content -> FeedContent(items = state.items) is FeedUiState.Error -> ErrorContent( message = state.message, onRetry = viewModel::loadFeed, ) } } ``` `collectAsStateWithLifecycle...Votes: 0GitHub stars: 549
- Android TestingUse `kotlinx-coroutines-test` to replace `Dispatchers.Main`, because `viewModelScope` launches on the main dispatcher. Inject the repository or use case and mock it with MockK; the test must not make a real network call or depend on a real database. ```kotlin @OptIn(ExperimentalCoroutinesApi::class) class MainDispatcherRule( val testDispatcher: TestDispatcher = UnconfinedTestDispatcher() ) : TestWatcher() { override fun starting(description: Description) { Dispatchers.setMain(testDispatcher) ...Votes: 0GitHub stars: 549
- Android TestingUse an Android instrumentation test with both `HiltAndroidRule` and `createAndroidComposeRule`. The Hilt rule must run first, and `hiltRule.inject()` must be called before the Activity or composable resolves the injected ViewModel. Use a test Activity annotated with `@AndroidEntryPoint` when the production Activity is not suitable. ```kotlin @AndroidEntryPoint class HiltTestActivity : ComponentActivity() ``` ```kotlin @HiltAndroidTest @RunWith(AndroidJUnit4::class) class FeedScreenTest { @get...Votes: 0GitHub stars: 549
- Android Testing`Thread.sleep` waits for an arbitrary amount of wall-clock time. It makes the suite slower, can still be too short on a busy emulator or CI worker, blocks the test thread, and does not prove that the repository, coroutine, worker, or UI has reached the state being asserted. That creates timing-dependent flaky tests and hides real synchronization problems. Wait for an observable condition with a bounded timeout. For Compose: ```kotlin composeRule.onNodeWithTag("load_button").performClick() com...Votes: 0GitHub stars: 549
- Android ToolingConfigure the Detekt complexity rules in the project Detekt config, for example `config/detekt/detekt.yml`: ```yaml build: maxIssues: 0 weights: complexity: 2 complexity: LongMethod: threshold: 30 LargeClass: threshold: 300 ``` `LongMethod.threshold` is the maximum method length and `LargeClass.threshold` is the maximum class length. With `build.maxIssues: 0`, any Detekt issue fails the Detekt task instead of being tolerated. Wire the config into the Gradle Kotlin DSL and make it part of the ...Votes: 0GitHub stars: 549
- Android ToolingNo. Do not allow `@Suppress("LongMethod")` in production code. The Android tooling standard explicitly treats production suppressions as an anti-pattern because they hide a complexity violation while leaving the code harder to maintain. Remove the suppression and fix the cause: split the method into focused functions, extract a cohesive collaborator, or simplify the control flow. Keep the `LongMethod` rule enabled and let Detekt fail the build when the configured threshold is exceeded. If the...Votes: 0GitHub stars: 549
- Android ToolingUse the Jlleitschuh Ktlint Gradle plugin, enable Android-aware formatting, and make formatting/checking explicit Gradle tasks: ```kotlin plugins { id("com.android.application") kotlin("android") id("org.jlleitschuh.gradle.ktlint") version "12.1.2" } ktlint { android.set(true) outputToConsole.set(true) ignoreFailures.set(false) } // Android's preBuild task runs before compilation, so this formats each build. tasks.named("preBuild") { dependsOn("ktlintFormat") } // Keep the non-mutating quality...Votes: 0GitHub stars: 549
- Android Xml ViewsEnable ViewBinding in the module and use the generated binding class instead of looking up each view by ID: ```kotlin // app/build.gradle.kts android { buildFeatures { viewBinding = true } } ``` For a layout named `fragment_home.xml`, Android generates `FragmentHomeBinding`. Bind the Fragment's view in `onViewCreated`, use the binding only while the view exists, and clear it in `onDestroyView`: ```kotlin class HomeFragment : Fragment(R.layout.fragment_home) { private var _binding: FragmentHom...Votes: 0GitHub stars: 549
- Android Xml ViewsUse `ListAdapter`, which wraps `AsyncListDiffer`, and describe how items are identified and when their contents changed. Submit each new snapshot with `submitList()`: ```kotlin data class Post( val id: Long, val title: String, ) class PostAdapter( private val onClick: (Post) -> Unit, ) : ListAdapter<Post, PostAdapter.ViewHolder>(DIFF_CALLBACK) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = ItemPostBinding.inflate( LayoutInflater.from(parent.con...Votes: 0GitHub stars: 549
- Android Xml ViewsFor a complex screen, replace the nested `LinearLayout` tree with one flat `ConstraintLayout`. Position views using constraints, chains, guidelines, or barriers instead of adding wrapper containers. A `0dp` dimension means “match the available space defined by the constraints.” For example, a title, subtitle, and action can be laid out without nested rows or columns: ```xml <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app=...Votes: 0GitHub stars: 549
- Angular ArchitectureOrganize the feature by business capability, not by file type. For example: ```text src/app/ ├── app.routes.ts └── features/ └── orders/ ├── orders.routes.ts ├── orders-page.component.ts ├── components/ │ └── order-list.component.ts ├── services/ │ └── orders-api.service.ts └── models/ └── order.ts ``` Lazy-load the feature from the root route configuration: ```ts // src/app/app.routes.ts import { Routes } from '@angular/router'; export const routes: Routes = [ { path: 'orders', loadChild...Votes: 0GitHub stars: 549
- Angular ArchitectureUse a shallow, feature-based structure. A typical standalone application looks like this: ```text src/ ├── app/ │ ├── app.config.ts # application-wide providers │ ├── app.routes.ts # root route table │ ├── app.component.ts # application shell │ ├── core/ # global singletons and infrastructure │ │ ├── auth/ │ │ ├── guards/ │ │ └── interceptors/ │ ├── shared/ # reusable, mostly presentational code │ │ ├── ui/ │ ...Votes: 0GitHub stars: 549
- Angular ArchitectureFor new Angular code, use standalone components, pipes, and directives. They make each component's dependencies explicit and eliminate the need for an NgModule as a feature assembly layer. In Angular 20 and later, standalone is the default; writing `standalone: true` explicitly is still clear when supporting or documenting older Angular versions. ```ts @Component({ selector: 'app-profile', standalone: true, imports: [ReactiveFormsModule, ProfileHeaderComponent], templateUrl: './profile.compon...Votes: 0GitHub stars: 549
- Angular ArchitectureUse a smart (container) component for data access, state, and feature actions. Use a dumb (presentational) component for rendering: it receives data through inputs and reports user intent through outputs. This keeps data concerns separate from rendering and makes the presentational component easy to test. ```ts // orders-page.component.ts: smart/container component @Component({ selector: 'app-orders-page', standalone: true, imports: [OrderListComponent], template: ` <app-order-list [orders]="...Votes: 0GitHub stars: 549
- Angular Architecture`loadComponent` is the route-level option for lazy-loading a standalone component. Put the route in the root route table (or a lazy feature route) and use a dynamic import: ```ts // src/app/app.routes.ts import { Routes } from '@angular/router'; export const routes: Routes = [ { path: 'dashboard', loadComponent: () => import('./features/dashboard/dashboard.component').then( (m) => m.DashboardComponent, ), }, ]; ``` The target component must be standalone: ```ts @Component({ selector: 'app-das...Votes: 0GitHub stars: 549
- Angular ArchitectureSeparate reusable code from application-wide infrastructure: ```text src/app/ ├── core/ │ ├── auth/auth.service.ts │ ├── guards/auth.guard.ts │ └── interceptors/auth.interceptor.ts ├── shared/ │ ├── ui/empty-state.component.ts │ ├── pipes/date-label.pipe.ts │ └── utils/format-currency.ts └── features/ └── billing/ └── services/billing-api.service.ts ``` Put global singletons and cross-cutting infrastructure in `core/`: authentication/session services, route guards, HTTP intercepto...Votes: 0GitHub stars: 549
- Angular ComponentsDeclare the component with `standalone: true`, import every directive or component it uses in the component's `imports` array, and use `OnPush` change detection. With Angular's built-in control flow, simple interpolation and event binding do not require `CommonModule`. ```ts import { ChangeDetectionStrategy, Component, input, output } from '@angular/core'; @Component({ selector: 'app-user-card', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: ` <artic...Votes: 0GitHub stars: 549
- Angular ComponentsUse Angular's built-in control-flow blocks (Angular 17+) instead of the structural directives `*ngIf` and `*ngFor`. Always give `@for` a stable tracking expression, normally a unique item id, and provide an `@empty` state when an empty collection needs a useful UI. ```ts import { ChangeDetectionStrategy, Component, input } from '@angular/core'; interface User { id: string; name: string; } @Component({ selector: 'app-user-list', standalone: true, imports: [], changeDetection: ChangeDetectionSt...Votes: 0GitHub stars: 549
- Angular ComponentsDeclare a required signal input with `input.required<T>()`. Angular will require the parent to bind it, and the component reads the current value by calling the signal, for example `userId()` rather than `userId`. ```ts import { booleanAttribute, ChangeDetectionStrategy, Component, input, } from '@angular/core'; @Component({ selector: 'app-user-badge', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: ` <span [attr.data-user-id]="userId()" [attr.aria-di...Votes: 0GitHub stars: 549
- Angular ComponentsPut host bindings in the component decorator's `host` metadata. Bind to signal values by calling the signal in the binding expression. This keeps host behavior declared with the component and avoids `@HostBinding` and direct `ElementRef` mutation. ```ts import { booleanAttribute, ChangeDetectionStrategy, Component, input, } from '@angular/core'; @Component({ selector: 'app-status-pill', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.active]': '...Votes: 0GitHub stars: 549
- Angular ComponentsDeclare a component output with `output<T>()` and emit values through its `.emit()` method. This replaces the decorator-based `@Output() EventEmitter<T>` pattern. ```ts import { ChangeDetectionStrategy, Component, input, output, } from '@angular/core'; interface SaveResult { id: string; } @Component({ selector: 'app-save-button', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: ` <button type="button" (click)="save()"> Save </button> `, }) export class...Votes: 0GitHub stars: 549
- Angular ComponentsSet `changeDetection: ChangeDetectionStrategy.OnPush` in every component decorator. OnPush limits checks to relevant changes, including signal updates read by the template, changed input references, and events handled by the component. ```ts import { ChangeDetectionStrategy, Component, signal, } from '@angular/core'; @Component({ selector: 'app-counter', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: ` <p>Count: {{ count() }}</p> <button type="button...Votes: 0GitHub stars: 549
- Angular ComponentsThe pattern separates orchestration from presentation: - A smart/container component injects services, owns loading/error/state decisions, and handles business actions. - A dumb/presentational component has no service dependencies. It receives data through signal inputs and reports user intent through `output()` events. For example, the presentational component can stay focused on rendering: ```ts import { ChangeDetectionStrategy, Component, input, output, } from '@angular/core'; interface Us...Votes: 0GitHub stars: 549
- Angular ComponentsUse `computed()` for derived values that depend on signals. A computed signal is memoized and recalculates when one of its tracked signal dependencies changes. Calling an arbitrary calculation from interpolation can repeat that work during change-detection checks. ```ts import { ChangeDetectionStrategy, Component, computed, input, signal, } from '@angular/core'; interface User { id: string; name: string; } @Component({ selector: 'app-filtered-users', standalone: true, imports: [], changeDetec...Votes: 0GitHub stars: 549