diff --git a/.github/workflows/android-fast.yml b/.github/workflows/android-fast.yml new file mode 100644 index 000000000..700b2b9af --- /dev/null +++ b/.github/workflows/android-fast.yml @@ -0,0 +1,79 @@ +name: Android Fast Build + +on: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: android-fast-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 45 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup JDK + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: zulu + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + gradle-home-cache-cleanup: true + + - name: Verify fast contracts + run: | + ./gradlew \ + :extension:api:jvmTest \ + :extension:runtime:test \ + :i18n:testDebugUnitTest + + - name: Build debug APKs + run: | + ./gradlew \ + :app:smartphone:assembleDebug \ + :app:tv:assembleDebug \ + :testing:extension-reference:assembleDebug + + - name: Verify 16 KB native compatibility + run: | + testing/bin/verify-android-16kb.sh \ + app/smartphone/build/outputs/apk/debug/*.apk \ + app/tv/build/outputs/apk/debug/*.apk \ + testing/extension-reference/build/outputs/apk/debug/*.apk + + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: android-debug-apks + if-no-files-found: error + retention-days: 14 + path: | + app/smartphone/build/outputs/apk/debug/*.apk + app/tv/build/outputs/apk/debug/*.apk + testing/extension-reference/build/outputs/apk/debug/*.apk + + - name: Upload To Telegram + uses: xireiki/channel-post@890c1d09635ae629aeffbed4f9716a5473eac896 # v1.0.10 + with: + bot_token: ${{ secrets.BOT_TOKEN }} + chat_id: ${{ secrets.CHAT_ID }} + api_id: ${{ secrets.API_ID }} + api_hash: ${{ secrets.API_HASH }} + large_file: true + method: sendFile + path: | + app/smartphone/build/outputs/apk/debug/*.apk + app/tv/build/outputs/apk/debug/*.apk + testing/extension-reference/build/outputs/apk/debug/*.apk diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index f98972f93..71553678d 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -6,16 +6,14 @@ on: paths-ignore: - '**.md' - '**.txt' - - '.github/**' - '.idea/**' - 'fastlane/**' - - '!.github/workflows/**' pull_request: branches: [ "master" ] workflow_dispatch: concurrency: - group: ${{ github.ref }} + group: android-release-${{ github.ref }} cancel-in-progress: true jobs: @@ -44,23 +42,53 @@ jobs: - name: Clean GMD run: ./gradlew cleanManagedDevices --unused-only - - name: Build production app + - name: Verify extension contracts + run: | + ./gradlew \ + :extension:api:jvmTest \ + :extension:runtime:test \ + :extension:sdk-android:testDebugUnitTest \ + :extension:transport-android:testDebugUnitTest + + - name: Verify localization contracts + run: ./gradlew :i18n:testDebugUnitTest + + - name: Validate connected UI harnesses + run: | + bash -n testing/bin/run-smartphone-provider-ui-matrix.sh + ./gradlew \ + :data:assembleDebugAndroidTest \ + :app:smartphone:assembleDebugAndroidTest \ + :app:tv:assembleDebugAndroidTest + + - name: Build smartphone release APK run: ./gradlew :app:smartphone:assembleRelease - - name: Build production TV app + - name: Build TV release APK run: ./gradlew :app:tv:assembleRelease + - name: Build reference extension release APK + run: ./gradlew :testing:extension-reference:assembleRelease + + - name: Verify 16 KB native compatibility + run: | + testing/bin/verify-android-16kb.sh \ + app/smartphone/build/outputs/published-apk/release/*.apk \ + app/tv/build/outputs/published-apk/release/*.apk \ + testing/extension-reference/build/outputs/apk/release/*.apk + - name: Upload uses: actions/upload-artifact@v4 with: if-no-files-found: error path: | - app/smartphone/build/outputs/apk/release/*.apk - app/tv/build/outputs/apk/release/*.apk + app/smartphone/build/outputs/published-apk/release/*.apk + app/tv/build/outputs/published-apk/release/*.apk + testing/extension-reference/build/outputs/apk/release/*.apk - name: Upload To Telegram if: github.event_name != 'pull_request' - uses: xireiki/channel-post@v1.0.10 + uses: xireiki/channel-post@890c1d09635ae629aeffbed4f9716a5473eac896 # v1.0.10 with: bot_token: ${{ secrets.BOT_TOKEN }} chat_id: ${{ secrets.CHAT_ID }} @@ -69,5 +97,6 @@ jobs: large_file: true method: sendFile path: | - app/smartphone/build/outputs/apk/release/*.apk - app/tv/build/outputs/apk/release/*.apk + app/smartphone/build/outputs/published-apk/release/*.apk + app/tv/build/outputs/published-apk/release/*.apk + testing/extension-reference/build/outputs/apk/release/*.apk diff --git a/.github/workflows/baseline-profiles.yml b/.github/workflows/baseline-profiles.yml index 377b38a2e..cc4054a3b 100644 --- a/.github/workflows/baseline-profiles.yml +++ b/.github/workflows/baseline-profiles.yml @@ -5,8 +5,12 @@ on: push: branches: [ "master" ] paths: + - 'build.gradle.kts' + - 'gradle/libs.versions.toml' + - 'gradle/wrapper/**' - 'app/smartphone/build.gradle.kts' - 'app/tv/build.gradle.kts' + - 'baselineprofile/**' - '.github/workflows/baseline-profiles.yml' permissions: @@ -40,15 +44,18 @@ jobs: if [ "$base" = "0000000000000000000000000000000000000000" ]; then base="$(git rev-list --max-parents=0 HEAD)" fi - if git diff --name-only "$base" HEAD -- .github/workflows/baseline-profiles.yml | grep -q .; then + if git diff --name-only "$base" HEAD -- \ + .github/workflows/baseline-profiles.yml \ + build.gradle.kts \ + gradle/libs.versions.toml \ + gradle/wrapper \ + app/smartphone/build.gradle.kts \ + app/tv/build.gradle.kts \ + baselineprofile | grep -q .; then echo "run=true" >> "$GITHUB_OUTPUT" exit 0 fi - if git diff "$base" HEAD -- app/smartphone/build.gradle.kts app/tv/build.gradle.kts | grep -E '^[-+][[:space:]]*version(Code|Name)[[:space:]]*='; then - echo "run=true" >> "$GITHUB_OUTPUT" - exit 0 - fi - echo "No app version change detected." + echo "No baseline profile inputs changed." echo "run=false" >> "$GITHUB_OUTPUT" - name: Setup JDK @@ -75,6 +82,15 @@ jobs: sudo chmod 660 /dev/kvm ls -l /dev/kvm + - name: Remove stale baseline profile output + if: steps.baseline-trigger.outputs.run == 'true' + run: | + rm -f \ + app/smartphone/src/main/generated/baselineProfiles/baseline-prof.txt \ + app/smartphone/src/main/generated/baselineProfiles/startup-prof.txt \ + app/tv/src/main/generated/baselineProfiles/baseline-prof.txt \ + app/tv/src/main/generated/baselineProfiles/startup-prof.txt + - name: Generate smartphone baseline profile if: steps.baseline-trigger.outputs.run == 'true' run: | @@ -97,6 +113,11 @@ jobs: if: steps.baseline-trigger.outputs.run == 'true' run: | set -euo pipefail + test -s app/smartphone/src/main/generated/baselineProfiles/baseline-prof.txt + test -s app/smartphone/src/main/generated/baselineProfiles/startup-prof.txt + test -s app/tv/src/main/generated/baselineProfiles/baseline-prof.txt + test -s app/tv/src/main/generated/baselineProfiles/startup-prof.txt + test ! -d app/smartphone/src/release/generated/baselineProfiles test ! -d app/tv/src/release/generated/baselineProfiles - name: Create baseline profile update pull request diff --git a/.github/workflows/native-packs.yml b/.github/workflows/native-packs.yml index 37c7b3894..cb49ad269 100644 --- a/.github/workflows/native-packs.yml +++ b/.github/workflows/native-packs.yml @@ -53,24 +53,70 @@ jobs: exit 1 fi - - name: Verify native load source protocol + - name: Verify 16 KB native compatibility run: | set -euo pipefail - if git grep -n 'm3u\.native-load-instrumentation\|NATIVE_PACK_COMMIT\|nativeLoadCommit' -- \ - native-load-gradle-plugin/src \ - app \ - data/src \ - data/build.gradle.kts \ - docs \ - native-load.yml \ - .github \ - ':!.github/workflows/native-packs.yml'; then - exit 1 - fi - if find native-packs -name '*.json' -print0 \ - | xargs -0 grep -n 'sourceCommit\|snapshotPath\|https://raw.githubusercontent.com\|native-packs/.*/release/'; then - exit 1 - fi + pack_id="$(awk '$1 == "id:" { print $2; exit }' native-load.yml)" + testing/bin/verify-android-16kb.sh "native-packs/$pack_id"/*.zip + + - name: Verify native pack identity pinning + run: | + set -euo pipefail + ./gradlew :data:generateReleaseBuildConfig --no-configuration-cache + python3 - <<'PY' + import hashlib + import re + import zipfile + from pathlib import Path + + config = Path( + "data/build/generated/source/buildConfig/release/com/m3u/data/BuildConfig.java" + ).read_text() + + def constant(name): + match = re.search( + rf'public static final String {name} = "([^"]*)";', + config, + ) + if not match: + raise SystemExit(f"Missing release identity constant: {name}") + return match.group(1) + + def entries(name): + encoded = constant(name) + return dict(entry.split("=", 1) for entry in encoded.split(";") if entry) + + pack_id = constant("NATIVE_PACK_ID") + pack_dir = Path("native-packs") / pack_id + manifest = pack_dir / f"m3u-codec-{pack_id}.json" + expected_manifest = hashlib.sha256(manifest.read_bytes()).hexdigest() + if constant("NATIVE_PACK_EXPECTED_MANIFEST_SHA256") != expected_manifest: + raise SystemExit("Release manifest identity is stale") + + expected_assets = entries("NATIVE_PACK_EXPECTED_ASSET_SHA256") + actual_assets = { + archive.name: hashlib.sha256(archive.read_bytes()).hexdigest() + for archive in sorted(pack_dir.glob("*.zip")) + } + if expected_assets != actual_assets: + raise SystemExit("Release asset identities are stale") + + actual_libraries = {} + for archive in sorted(pack_dir.glob("*.zip")): + with zipfile.ZipFile(archive) as zipped: + for name in sorted(zipped.namelist()): + if not name.endswith("/"): + actual_libraries[f"{archive.name}/{name}"] = hashlib.sha256( + zipped.read(name) + ).hexdigest() + if entries("NATIVE_PACK_EXPECTED_LIBRARY_SHA256") != actual_libraries: + raise SystemExit("Release library identities are stale") + PY + git grep -q 'expectedManifestSha256' -- data/src/main/java/com/m3u/data/codec/CodecPackRepository.kt + git grep -q 'expectedAssetSha256' -- data/src/main/java/com/m3u/data/codec/CodecPackRepository.kt + git grep -q 'expectedLibrarySha256' -- \ + data/src/main/java/com/m3u/data/codec/CodecPackRepository.kt \ + data/src/main/java/com/m3u/data/codec/CodecNativeLoader.kt - name: Verify committed native packs run: | diff --git a/.gitignore b/.gitignore index 47e9967b0..cb0e32470 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ jks.txt __pycache__/ *.pyc testing/mock-server/bin/ +testing/mock-server/build/ +testing/extension-reference/build/ +samples/*/build/ diff --git a/README.md b/README.md index 0ea4994c0..57d44433c 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,11 @@ It is made for users who want a clean, practical, ad-free IPTV app that works we - [Nightly Build](https://nightly.link/oxyroid/M3UAndroid/workflows/android/master/artifact.zip) - [Telegram Channel](https://t.me/m3u_android) +## Extensions + +- [Extension documentation (English)](docs/extensions/README.md) +- [插件文档(简体中文)](docs/extensions/README.zh-CN.md) + ## License M3UAndroid is an open-source project licensed under the [GNU General Public License v3.0](LICENSE). diff --git a/app/extension/.gitignore b/app/extension/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/app/extension/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/app/extension/build.gradle.kts b/app/extension/build.gradle.kts deleted file mode 100644 index 108995a30..000000000 --- a/app/extension/build.gradle.kts +++ /dev/null @@ -1,65 +0,0 @@ -plugins { - alias(libs.plugins.com.android.application) - alias(libs.plugins.org.jetbrains.kotlin.android) - alias(libs.plugins.compose.compiler) - alias(libs.plugins.com.google.devtools.ksp) -} - -android { - namespace = "com.m3u.extension" - compileSdk = 36 - - defaultConfig { - applicationId = "com.m3u.extension" - minSdk = 26 - targetSdk = 35 - versionCode = 1 - versionName = "1.0" - manifestPlaceholders += mapOf( - "description" to "Provides the ability to parse playlists using the standard TXT IPTV protocol", - "version" to "1", - "mainClass" to ".MainActivity" - ) - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - isMinifyEnabled = false - proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro" - ) - signingConfig = signingConfigs.getByName("debug") - } - } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - buildFeatures { - compose = true - } -} - -dependencies { - implementation(libs.m3u.extension.api) - implementation(libs.m3u.extension.annotation) - ksp(libs.m3u.extension.processor) - - implementation(libs.androidx.core.ktx) - implementation(libs.androidx.lifecycle.runtime.ktx) - - // compose - implementation(platform(libs.androidx.compose.bom)) - implementation(libs.androidx.compose.foundation) - implementation(libs.androidx.compose.foundation.layout) - implementation(libs.androidx.compose.material.icons.extended) - implementation(libs.androidx.compose.runtime) - implementation(libs.androidx.compose.ui.util) - implementation(libs.androidx.navigation.compose) - - // compose-material3 - implementation(libs.androidx.compose.material3) - -} diff --git a/app/extension/proguard-rules.pro b/app/extension/proguard-rules.pro deleted file mode 100644 index 36b7effad..000000000 --- a/app/extension/proguard-rules.pro +++ /dev/null @@ -1,25 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile - --keep class com.squareup.wire.** { *; } --keep class com.m3u.extension.api.model.** { *; } --keep class * extends com.squareup.wire.ProtoAdapter \ No newline at end of file diff --git a/app/extension/src/main/AndroidManifest.xml b/app/extension/src/main/AndroidManifest.xml deleted file mode 100644 index 29127b4e4..000000000 --- a/app/extension/src/main/AndroidManifest.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/extension/src/main/java/com/m3u/extension/MainActivity.kt b/app/extension/src/main/java/com/m3u/extension/MainActivity.kt deleted file mode 100644 index 65044251a..000000000 --- a/app/extension/src/main/java/com/m3u/extension/MainActivity.kt +++ /dev/null @@ -1,190 +0,0 @@ -package com.m3u.extension - -import android.content.Intent -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge -import androidx.compose.animation.animateColorAsState -import androidx.compose.animation.core.animateIntAsState -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Button -import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateListOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.LineBreak -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.m3u.extension.api.CallTokenConst -import com.m3u.extension.api.RemoteClient -import com.m3u.extension.api.business.InfoApi -import com.m3u.extension.api.business.SubscribeApi -import com.m3u.extension.api.model.AddPlaylistRequest -import com.m3u.extension.ui.theme.M3UTheme -import kotlinx.coroutines.launch - -class MainActivity : ComponentActivity() { - private val client = RemoteClient() - private val infoApi = client.create() - private val subscribeApi = client.create() - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - enableEdgeToEdge() - var callToken by mutableStateOf(handleArguments(intent)) - val commands = mutableStateListOf() - - setContent { - M3UTheme { - val coroutineScope = rememberCoroutineScope() - val isConnected by client.isConnectedObservable.collectAsStateWithLifecycle(false) - DisposableEffect(Unit) { - onDispose { - if (isConnected) { - client.disconnect(this@MainActivity) - } - } - } - Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - Column( - modifier = Modifier - .fillMaxSize() - .padding(innerPadding) - .padding(16.dp) - ) { - val lazyListState = rememberLazyListState() - LaunchedEffect(commands.size) { - lazyListState.scrollToItem(Int.MAX_VALUE) - } - LazyColumn( - state = lazyListState, - modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(8.dp)) - .background(Color.Black) - .weight(1f), - contentPadding = PaddingValues(8.dp) - ) { - itemsIndexed(commands) { index, command -> - val isFocused = index == commands.lastIndex - val fontWeight by animateIntAsState(if (isFocused) 700 else 400) - val color by animateColorAsState(if (isFocused) Color.Yellow else Color.White) - - Text( - text = "> $command", - fontFamily = FontFamily.Monospace, - color = color, - fontWeight = FontWeight(fontWeight), - modifier = Modifier.weight(1f), - style = LocalTextStyle.current.copy( - lineBreak = LineBreak.Paragraph - ) - ) - } - } - Button( - enabled = callToken != null, - onClick = { - val callToken = callToken - if (!isConnected && callToken != null) { - client.connect( - context = this@MainActivity, - targetPackageName = callToken.packageName, - targetClassName = callToken.className, - accessKey = callToken.accessKey - ) - } else { - client.disconnect(this@MainActivity) - } - } - ) { - Text( - text = when { - callToken == null -> "No CallToken" - isConnected -> "Disconnect" - else -> "Connect" - } - ) - } - Button( - enabled = isConnected, - onClick = { - coroutineScope.launch { - commands += infoApi.getAppInfo().toString() - } - } - ) { - Text( - text = "GetAppInfo" - ) - } - Button( - enabled = isConnected, - onClick = { - coroutineScope.launch { - commands += infoApi.getModules().toString() - } - } - ) { - Text( - text = "GetModulesResponse" - ) - } - Button( - enabled = isConnected, - onClick = { - coroutineScope.launch { - commands += subscribeApi.addPlaylist( - AddPlaylistRequest( - url = "https://example.com/playlist.m3u?time=${System.currentTimeMillis()}", - title = "Test Playlist ${System.currentTimeMillis()}", - user_agent = "Test User Agent" - ) - ).toString() - } - } - ) { - Text( - text = "AddPlaylist" - ) - } - } - } - } - } - } - - private fun handleArguments(intent: Intent): CallToken? { - val packageName = intent.getStringExtra(CallTokenConst.PACKAGE_NAME) ?: return null - val className = intent.getStringExtra(CallTokenConst.CLASS_NAME) ?: return null - val accessKey = intent.getStringExtra(CallTokenConst.ACCESS_KEY) ?: return null - return CallToken(packageName, className, accessKey) - } -} - -private data class CallToken( - val packageName: String, - val className: String, - val accessKey: String -) \ No newline at end of file diff --git a/app/extension/src/main/java/com/m3u/extension/ui/theme/Color.kt b/app/extension/src/main/java/com/m3u/extension/ui/theme/Color.kt deleted file mode 100644 index f67fceb93..000000000 --- a/app/extension/src/main/java/com/m3u/extension/ui/theme/Color.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.m3u.extension.ui.theme - -import androidx.compose.ui.graphics.Color - -val Purple80 = Color(0xFFD0BCFF) -val PurpleGrey80 = Color(0xFFCCC2DC) -val Pink80 = Color(0xFFEFB8C8) - -val Purple40 = Color(0xFF6650a4) -val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/extension/src/main/java/com/m3u/extension/ui/theme/Theme.kt b/app/extension/src/main/java/com/m3u/extension/ui/theme/Theme.kt deleted file mode 100644 index 6608a7c6b..000000000 --- a/app/extension/src/main/java/com/m3u/extension/ui/theme/Theme.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.m3u.extension.ui.theme - -import android.app.Activity -import android.os.Build -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.dynamicDarkColorScheme -import androidx.compose.material3.dynamicLightColorScheme -import androidx.compose.material3.lightColorScheme -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext - -private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 -) - -private val LightColorScheme = lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40 - - /* Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), - onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), - */ -) - -@Composable -fun M3UTheme( - darkTheme: Boolean = isSystemInDarkTheme(), - // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, - content: @Composable () -> Unit -) { - val colorScheme = when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { - val context = LocalContext.current - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - } - - darkTheme -> DarkColorScheme - else -> LightColorScheme - } - - MaterialTheme( - colorScheme = colorScheme, - typography = Typography, - content = content - ) -} \ No newline at end of file diff --git a/app/extension/src/main/java/com/m3u/extension/ui/theme/Type.kt b/app/extension/src/main/java/com/m3u/extension/ui/theme/Type.kt deleted file mode 100644 index f384cd7c2..000000000 --- a/app/extension/src/main/java/com/m3u/extension/ui/theme/Type.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.m3u.extension.ui.theme - -import androidx.compose.material3.Typography -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.sp - -// Set of Material typography styles to start with -val Typography = Typography( - bodyLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.5.sp - ) - /* Other default text styles to override - titleLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp - ), - labelSmall = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Medium, - fontSize = 11.sp, - lineHeight = 16.sp, - letterSpacing = 0.5.sp - ) - */ -) \ No newline at end of file diff --git a/app/extension/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/extension/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 345888d26..000000000 --- a/app/extension/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/extension/src/main/res/mipmap-hdpi/ic_launcher.png b/app/extension/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 6f3fe86a7..000000000 Binary files a/app/extension/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-hdpi/ic_launcher_background.png b/app/extension/src/main/res/mipmap-hdpi/ic_launcher_background.png deleted file mode 100644 index f8103ee0a..000000000 Binary files a/app/extension/src/main/res/mipmap-hdpi/ic_launcher_background.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/extension/src/main/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index cb9ceb75a..000000000 Binary files a/app/extension/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png b/app/extension/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png deleted file mode 100644 index 8ddd48485..000000000 Binary files a/app/extension/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-mdpi/ic_launcher.png b/app/extension/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 98926a8b8..000000000 Binary files a/app/extension/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-mdpi/ic_launcher_background.png b/app/extension/src/main/res/mipmap-mdpi/ic_launcher_background.png deleted file mode 100644 index f8e4e4c6c..000000000 Binary files a/app/extension/src/main/res/mipmap-mdpi/ic_launcher_background.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/extension/src/main/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index 3f52e8a9c..000000000 Binary files a/app/extension/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png b/app/extension/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png deleted file mode 100644 index fab321ef0..000000000 Binary files a/app/extension/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/extension/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index f31cb27ee..000000000 Binary files a/app/extension/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/app/extension/src/main/res/mipmap-xhdpi/ic_launcher_background.png deleted file mode 100644 index 106f37ba7..000000000 Binary files a/app/extension/src/main/res/mipmap-xhdpi/ic_launcher_background.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/extension/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 1eee92ece..000000000 Binary files a/app/extension/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png b/app/extension/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 3c4bba5da..000000000 Binary files a/app/extension/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index f985fd24a..000000000 Binary files a/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher_background.png deleted file mode 100644 index 6ad6869b5..000000000 Binary files a/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 406873f5b..000000000 Binary files a/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 7e1ca83a4..000000000 Binary files a/app/extension/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 154f89880..000000000 Binary files a/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png deleted file mode 100644 index b28b839a9..000000000 Binary files a/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 4d620ba44..000000000 Binary files a/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png deleted file mode 100644 index 2cc11f2c2..000000000 Binary files a/app/extension/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png and /dev/null differ diff --git a/app/extension/src/main/res/values/colors.xml b/app/extension/src/main/res/values/colors.xml deleted file mode 100644 index f8c6127d3..000000000 --- a/app/extension/src/main/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 - #FF000000 - #FFFFFFFF - \ No newline at end of file diff --git a/app/extension/src/main/res/values/strings.xml b/app/extension/src/main/res/values/strings.xml deleted file mode 100644 index a33a89b12..000000000 --- a/app/extension/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - IPTV TxT - \ No newline at end of file diff --git a/app/extension/src/main/res/values/themes.xml b/app/extension/src/main/res/values/themes.xml deleted file mode 100644 index 667b9e345..000000000 --- a/app/extension/src/main/res/values/themes.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - -