################################################################################
# VirtuesDimens Dynamic — principal consumer-rules.pro (virtues-dimens-dynamic)
#
# Bundled INSIDE the AAR and merged into the consuming app's R8/ProGuard run when:
#
#   implementation("ag.virtues.dimens:virtues-dimens-dynamic:x.y.z")
#
# Satellite AARs (virtues-dimens-dynamic-<strategy>) ship their own consumer-rules.pro
# for that strategy's public API; core keeps below remain the shared baseline.
#
# Design principle: keep the minimum surface needed for correctness.
# Do NOT impose -optimizationpasses or -allowaccessmodification here —
# those are app-level decisions, not library decisions.
################################################################################


################################################################################
# 1. PUBLIC API SURFACE (principal = common + scaled + plain packages present here)
#
#    Classes under .code.** / .compose.** in this AAR are the scaled (+ related)
#    developer-facing API. Satellite strategies keep their own packages in their
#    own AARs. R8 must not rename or remove public/protected members the app calls
#    by name (Kotlin extensions, @Composable functions, Java-style static methods).
#
#    -keep (not -keepnames) because full mode may also _remove_ members that it
#    determines are unreachable from the app's entry points. We want to prevent
#    both removal and renaming.
################################################################################

-keepnames public class com.virtues.dimens.dynamic.code.** { public protected *; }
-keepnames public class com.virtues.dimens.dynamic.compose.** { public protected *; }
-keepnames public class com.virtues.dimens.dynamic.common.** { public protected *; }


################################################################################
# 2. DIMENCACHE — @PublishedApi internal members
#
#    Kotlin `inline fun` expands into the consuming app's bytecode at compile
#    time. The inlined body references @PublishedApi internal members of
#    DimenCache directly: factors, shards, CT_* int constants, buildKey(),
#    getOrPutInternal(), currentScale, currentArMultiplier, etc.
#
#    Without these keeps, R8 full mode sees those members referenced only from
#    the app's expanded bytecode — not from any non-inline path — and may decide
#    they are dead in the library's class files, removing them before the app
#    gets a chance to use them. The result is NoSuchFieldError / NoSuchMethod-
#    Error at runtime.
#
#    We keep the entire DimenCache object and its nested classes rather than
#    listing members one by one, so that future additions to the @PublishedApi
#    surface are automatically protected without a consumer-rules update.
################################################################################

-keep class com.virtues.dimens.dynamic.core.DimenCache { *; }
-keep class com.virtues.dimens.dynamic.core.DimenCache$* { *; }

# Strategy factor SPI — satellites register contributors; R8 must not strip the registry
# or SharedScreenMetrics used from inline / cross-module call sites. Kept by NAME only:
# members are referenced directly (no reflection/ServiceLoader is used), so renaming must
# be prevented but dead members may still be removed. -keepnames (not -keep) is enough:
# call sites are always in the same R8 pass as the library classes.
-keepnames class com.virtues.dimens.dynamic.core.StrategyFactorRegistry { *; }
-keepnames class com.virtues.dimens.dynamic.core.SharedScreenMetrics { *; }
-keepnames class com.virtues.dimens.dynamic.core.StrategyFactorContributor { *; }

# ScreenFactors padding fields (_p0.._p7): R8 full mode strips @JvmField fields
# it identifies as write-only (never read by name). These fields are never read —
# their only purpose is to occupy memory and prevent CPU false sharing on ARM64.
# ScreenFactors is retained for source compatibility only; the active kernel reads
# the snapshot-partitioned DimenMetrics (3.1.7+), so this rule is belt-and-braces.
-keepclassmembers class com.virtues.dimens.dynamic.core.DimenCache$ScreenFactors {
    <fields>;
}

# CalcType / ValueType ordinals are packed into 64-bit cache keys. They are
# nested enums under DimenCache — already fully covered by the DimenCache$*
# rule above (no separate enum member rules: R8 treats **[] $VALUES as
# non-matching on Kotlin enums and reports "matches no class members").


################################################################################
# 3. COMMON ENUMS
#
#    DpQualifier, Inverter, Orientation, UiModeType, UnitType ordinals are
#    encoded into cache keys and used in when-expressions throughout the
#    builder chain. Renaming or reordering entries causes wrong dispatch and
#    silent scaling errors that are extremely hard to debug.
################################################################################

# Use <fields>/<methods> instead of Java-style values/valueOf/$VALUES patterns:
# Kotlin stores $VALUES privately; the $ in **[] $VALUES confuses R8's matcher.
-keepclassmembers enum com.virtues.dimens.dynamic.common.* {
    <fields>;
    <methods>;
}

# Ordinals used in resize math — full keep so private enum synthetics survive.
-keepnames class com.virtues.dimens.dynamic.core.AutoResizePercentBasis { *; }


################################################################################
# 4. SEALED CLASS — ResizeBound
#
#    R8 full mode eliminates sealed subclasses it never sees instantiated in the
#    current analysis scope. ResizeBound.FixedDp, FixedSp and Percent are all
#    instantiated inside the library's own helper functions (resizeFixedDp, etc.)
#    which the app calls — but R8 may not trace through those constructors when
#    processing the app if the helpers are inlined away differently.
#    Keeping the sealed hierarchy costs < 200 bytes and prevents runtime ClassNot-
#    FoundException in when-expressions over ResizeBound.
################################################################################

-keepnames class com.virtues.dimens.dynamic.core.ResizeBound { *; }
-keepnames class com.virtues.dimens.dynamic.core.ResizeBound$* { *; }
-keepnames class com.virtues.dimens.dynamic.core.ResizeBoundKt { *; }


################################################################################
# 5. CORE PLUMBING — Compose integration
#
#    Renaming is prevented for the whole core package by name; the only class
#    that needs full -keep retention is DimenCache (see §2 — its members are
#    referenced from inlined @PublishedApi bodies the R8 analysis can lose).
#    Everything else in core is referenced directly at call sites, so dead
#    members may still be removed, but names are never renamed.
################################################################################

# 5.1 CompositionLocals (VirtuesDimensProvider), stamps, plumbing, AR lookup and
#     design constants are all reachable by direct reference; name preservation
#     is all that is required to keep them callable from consuming apps.
-keepnames class com.virtues.dimens.dynamic.core.CompositionLocalsKt { *; }
-keepnames class com.virtues.dimens.dynamic.core.ComposeDimenRememberKt { *; }
-keepnames class com.virtues.dimens.dynamic.core.ComposeRememberStampsKt { *; }
-keepnames class com.virtues.dimens.dynamic.core.DimenCalculationPlumbing { *; }
-keepnames class com.virtues.dimens.dynamic.core.ResizeMathKt { *; }
-keepnames class com.virtues.dimens.dynamic.core.PercentSpaceMathKt { *; }
-keepnames class com.virtues.dimens.dynamic.core.AspectRatioLookup { *; }
-keepnames class com.virtues.dimens.dynamic.core.AspectRatioLookupKt { *; }
-keepnames class com.virtues.dimens.dynamic.core.DesignScaleConstants { *; }
-keepnames class com.virtues.dimens.dynamic.core.DimenMetrics { *; }


################################################################################
# 6. KOTLIN METADATA
#
#    kotlin.Metadata is the annotation the Kotlin compiler writes on every
#    class. Without it, kotlinx.reflect, Compose tooling, and some annotation
#    processors treat the library's classes as plain Java and break. Kotlin's
#    own gradle plugin normally adds this rule, but explicit is safer.
################################################################################

-keep class kotlin.Metadata { *; }
-keep class kotlin.jvm.internal.** { *; }


################################################################################
# 7. PARCELIZE / SERIALIZABLE
#
#    VirtuesDimens does not currently expose Parcelable or Serializable public types,
#    but these rules protect any future addition. -keepnames (not -keep) is
#    sufficient here: we only need to prevent renaming, not removal, for classes
#    the app never instantiates directly.
################################################################################

-keepnames class * implements android.os.Parcelable
-keepnames interface * implements android.os.Parcelable
-keepclassmembers class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}

-keepnames class * implements java.io.Serializable
-keepnames interface * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}


################################################################################
# 8. PROFILE INSTALLER / TRACING (reflection-driven)
#
#    androidx.profileinstaller (pulled in by macrobenchmark apps and by apps
#    embedding baseline profiles) and androidx.startup invoke androidx.tracing
#    at runtime. In R8 full mode these call sites are invisible to static
#    analysis, so both packages get stripped from a minified release and the
#    process crashes with NoClassDefFoundError: androidx/tracing/Trace the
#    moment instrumentation (or the profile installer) starts.
#    Keeping both packages adds <10 KB and protects any app that uses
#    BaselineProfileRule or embedded baseline profiles.
################################################################################

-keep class androidx.tracing.** { *; }
-keep class androidx.profileinstaller.** { *; }


################################################################################
# 9. SUPPRESS NOTES — full mode is noisier than compat mode
#
#    -dontnote SUPPRESSES MESSAGES ONLY. It does not remove any protection.
#    These notes appear because android.jar stubs are present in the library
#    classpath but some implementation classes are not. All are safe to ignore.
################################################################################

-dontnote android.**
-dontnote androidx.**
-dontnote kotlin.**
-dontnote kotlinx.**
-dontwarn sun.misc.**
-dontnote sun.misc.**
