diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 27d8a144..8edf38f7 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -82,6 +82,9 @@ dependencies {
implementation(libs.compose.activity)
implementation(libs.compose.lifecycle.viewmodel)
implementation(libs.compose.livedata)
+ implementation(libs.compose.navigation)
+
+ implementation(libs.accompanist.adaptive)
implementation(libs.core.ktx)
implementation(libs.appcompat)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 81f71e3e..c0d5eb12 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,22 +5,34 @@
-
-
+
+
-
+
-
-
-
+
+
-
-
-
+
+
+ tools:ignore="UnusedAttribute"
+ tools:replace="android:theme">
@@ -51,15 +63,18 @@
-
-
-
@@ -75,8 +90,8 @@
+ android:exported="true"
+ android:parentActivityName=".ui.MainComposeActivity">
@@ -85,8 +100,8 @@
-
-
+
+
@@ -96,8 +111,8 @@
-
-
+
+
@@ -177,13 +192,13 @@
-
+ android:label="@string/settings_title" />
+ android:exported="true"
+ android:theme="@android:style/Theme.Material.Light.NoActionBar"
+ android:windowSoftInputMode="adjustResize">
@@ -191,7 +206,6 @@
-
diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt
index d91450e9..0c176dd8 100644
--- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt
+++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt
@@ -26,7 +26,6 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
-import android.util.Log
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
@@ -38,22 +37,22 @@ import com.google.android.gms.common.GooglePlayServicesRepairableException
import com.google.android.gms.security.ProviderInstaller
import com.google.firebase.FirebaseApp
import com.google.firebase.crashlytics.FirebaseCrashlytics
-import kotlinx.coroutines.*
import okhttp3.Dispatcher
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import xyz.quaver.io.FileX
-import xyz.quaver.pupil.hitomi.evaluationContext
-import xyz.quaver.pupil.hitomi.readText
import xyz.quaver.pupil.types.Tag
-import xyz.quaver.pupil.util.*
+import xyz.quaver.pupil.util.Preferences
+import xyz.quaver.pupil.util.SavedSet
+import xyz.quaver.pupil.util.getProxyInfo
+import xyz.quaver.pupil.util.preferences
+import xyz.quaver.pupil.util.proxyInfo
import java.io.File
-import java.net.URL
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertificateFactory
-import java.util.*
+import java.util.UUID
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
@@ -94,16 +93,19 @@ fun getSSLContext(context: Context): SSLContext {
keyStore.setCertificateEntry("isrgrootx1", certificate)
- val defaultTrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ val defaultTrustManagerFactory =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
defaultTrustManagerFactory.init(null as KeyStore?)
- defaultTrustManagerFactory.trustManagers.filterIsInstance(X509TrustManager::class.java).forEach { trustManager ->
- trustManager.acceptedIssuers.forEach { acceptedIssuer ->
- keyStore.setCertificateEntry(acceptedIssuer.subjectDN.name, acceptedIssuer)
+ defaultTrustManagerFactory.trustManagers.filterIsInstance()
+ .forEach { trustManager ->
+ trustManager.acceptedIssuers.forEach { acceptedIssuer ->
+ keyStore.setCertificateEntry(acceptedIssuer.subjectDN.name, acceptedIssuer)
+ }
}
- }
- val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ val trustManagerFactory =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(keyStore)
val sslContext = SSLContext.getInstance("TLS")
@@ -125,7 +127,7 @@ class Pupil : Application() {
preferences = PreferenceManager.getDefaultSharedPreferences(this)
- val userID = Preferences["user_id", ""].let { userID ->
+ val userID = Preferences["user_id", ""].let { userID ->
if (userID.isEmpty()) UUID.randomUUID().toString().also { Preferences["user_id"] = it }
else userID
}
@@ -142,7 +144,10 @@ class Pupil : Application() {
.proxyInfo(proxyInfo)
.addInterceptor { chain ->
val request = chain.request().newBuilder()
- .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36")
+ .addHeader(
+ "User-Agent",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"
+ )
.header("Referer", "https://hitomi.la/")
.build()
@@ -178,7 +183,8 @@ class Pupil : Application() {
histories = SavedSet(File(ContextCompat.getDataDir(this), "histories.json"), 0)
favorites = SavedSet(File(ContextCompat.getDataDir(this), "favorites.json"), 0)
- favoriteTags = SavedSet(File(ContextCompat.getDataDir(this), "favorites_tags.json"), Tag.parse(""))
+ favoriteTags =
+ SavedSet(File(ContextCompat.getDataDir(this), "favorites_tags.json"), Tag.parse(""))
searchHistory = SavedSet(File(ContextCompat.getDataDir(this), "search_histories.json"), "")
favoriteTags.filter { it.tag.contains('_') }.forEach {
@@ -209,46 +215,73 @@ class Pupil : Application() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- manager.createNotificationChannel(NotificationChannel("download", getString(R.string.channel_download), NotificationManager.IMPORTANCE_LOW).apply {
- description = getString(R.string.channel_download_description)
- enableLights(false)
- enableVibration(false)
- lockscreenVisibility = Notification.VISIBILITY_SECRET
- })
+ manager.createNotificationChannel(
+ NotificationChannel(
+ "download",
+ getString(R.string.channel_download),
+ NotificationManager.IMPORTANCE_LOW
+ ).apply {
+ description = getString(R.string.channel_download_description)
+ enableLights(false)
+ enableVibration(false)
+ lockscreenVisibility = Notification.VISIBILITY_SECRET
+ })
- manager.createNotificationChannel(NotificationChannel("downloader", getString(R.string.channel_downloader), NotificationManager.IMPORTANCE_LOW).apply {
- description = getString(R.string.channel_downloader_description)
- enableLights(false)
- enableVibration(false)
- lockscreenVisibility = Notification.VISIBILITY_SECRET
- })
+ manager.createNotificationChannel(
+ NotificationChannel(
+ "downloader",
+ getString(R.string.channel_downloader),
+ NotificationManager.IMPORTANCE_LOW
+ ).apply {
+ description = getString(R.string.channel_downloader_description)
+ enableLights(false)
+ enableVibration(false)
+ lockscreenVisibility = Notification.VISIBILITY_SECRET
+ })
- manager.createNotificationChannel(NotificationChannel("update", getString(R.string.channel_update), NotificationManager.IMPORTANCE_HIGH).apply {
- description = getString(R.string.channel_update_description)
- enableLights(true)
- enableVibration(true)
- lockscreenVisibility = Notification.VISIBILITY_SECRET
- })
+ manager.createNotificationChannel(
+ NotificationChannel(
+ "update",
+ getString(R.string.channel_update),
+ NotificationManager.IMPORTANCE_HIGH
+ ).apply {
+ description = getString(R.string.channel_update_description)
+ enableLights(true)
+ enableVibration(true)
+ lockscreenVisibility = Notification.VISIBILITY_SECRET
+ })
- manager.createNotificationChannel(NotificationChannel("import", getString(R.string.channel_update), NotificationManager.IMPORTANCE_LOW).apply {
- description = getString(R.string.channel_update_description)
- enableLights(false)
- enableVibration(false)
- lockscreenVisibility = Notification.VISIBILITY_SECRET
- })
+ manager.createNotificationChannel(
+ NotificationChannel(
+ "import",
+ getString(R.string.channel_update),
+ NotificationManager.IMPORTANCE_LOW
+ ).apply {
+ description = getString(R.string.channel_update_description)
+ enableLights(false)
+ enableVibration(false)
+ lockscreenVisibility = Notification.VISIBILITY_SECRET
+ })
- manager.createNotificationChannel(NotificationChannel("transfer", getString(R.string.channel_transfer), NotificationManager.IMPORTANCE_LOW).apply {
- description = getString(R.string.channel_transfer_description)
- enableLights(false)
- enableVibration(false)
- lockscreenVisibility = Notification.VISIBILITY_SECRET
- })
+ manager.createNotificationChannel(
+ NotificationChannel(
+ "transfer",
+ getString(R.string.channel_transfer),
+ NotificationManager.IMPORTANCE_LOW
+ ).apply {
+ description = getString(R.string.channel_transfer_description)
+ enableLights(false)
+ enableVibration(false)
+ lockscreenVisibility = Notification.VISIBILITY_SECRET
+ })
}
- AppCompatDelegate.setDefaultNightMode(when (Preferences.get("dark_mode")) {
- true -> AppCompatDelegate.MODE_NIGHT_YES
- false -> AppCompatDelegate.MODE_NIGHT_NO
- })
+ AppCompatDelegate.setDefaultNightMode(
+ when (Preferences.get("dark_mode")) {
+ true -> AppCompatDelegate.MODE_NIGHT_YES
+ false -> AppCompatDelegate.MODE_NIGHT_NO
+ }
+ )
super.onCreate()
}
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt
index 120a9986..959f8ae9 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt
@@ -23,9 +23,11 @@ import android.os.Bundle
import android.os.PersistableBundle
import android.view.WindowManager
import androidx.activity.ComponentActivity
+import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.CallSuper
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.WindowCompat
import xyz.quaver.pupil.util.LockManager
import xyz.quaver.pupil.util.Preferences
@@ -41,8 +43,11 @@ open class BaseComponentActivity : ComponentActivity() {
}
@CallSuper
- override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
- super.onCreate(savedInstanceState, persistentState)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ enableEdgeToEdge()
+ super.onCreate(savedInstanceState)
+
+ WindowCompat.setDecorFitsSystemWindows(window, false)
locked = !LockManager(this).locks.isNullOrEmpty()
}
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/MainComposeActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/MainComposeActivity.kt
new file mode 100644
index 00000000..a5c6c6c3
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/MainComposeActivity.kt
@@ -0,0 +1,44 @@
+package xyz.quaver.pupil.ui
+
+import android.os.Bundle
+import androidx.activity.compose.setContent
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.activity.viewModels
+import androidx.compose.runtime.getValue
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.google.accompanist.adaptive.calculateDisplayFeatures
+import xyz.quaver.pupil.ui.compose.MainApp
+import xyz.quaver.pupil.ui.theme.AppTheme
+import xyz.quaver.pupil.ui.viewmodel.MainViewModel
+import xyz.quaver.pupil.util.requestNotificationPermission
+import xyz.quaver.pupil.util.showNotificationPermissionExplanationDialog
+
+class MainComposeActivity : BaseComponentActivity() {
+ private val requestNotificationPermissionLauncher =
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
+ if (!isGranted) {
+ showNotificationPermissionExplanationDialog(this)
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ requestNotificationPermission(this, requestNotificationPermissionLauncher, false)
+
+ val viewModel: MainViewModel by viewModels()
+
+ setContent {
+ val displayFeatures = calculateDisplayFeatures(this)
+
+ val uiState by viewModel.searchState.collectAsStateWithLifecycle()
+
+ AppTheme {
+ MainApp(
+ uiState = uiState,
+ displayFeatures = displayFeatures
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/compose/MainApp.kt b/app/src/main/java/xyz/quaver/pupil/ui/compose/MainApp.kt
new file mode 100644
index 00000000..8e7df129
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/compose/MainApp.kt
@@ -0,0 +1,20 @@
+package xyz.quaver.pupil.ui.compose
+
+import androidx.compose.material3.Text
+import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
+import androidx.compose.runtime.Composable
+import androidx.navigation.NavController
+import androidx.navigation.compose.rememberNavController
+import androidx.window.core.layout.WindowSizeClass
+import androidx.window.layout.DisplayFeature
+import xyz.quaver.pupil.ui.viewmodel.SearchState
+
+@Composable
+fun MainApp(
+ uiState: SearchState,
+ displayFeatures: List,
+ navController: NavController = rememberNavController(),
+ windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass,
+) {
+ Text("Hello, World!")
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/theme/Color.kt b/app/src/main/java/xyz/quaver/pupil/ui/theme/Color.kt
new file mode 100644
index 00000000..319fd523
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/theme/Color.kt
@@ -0,0 +1,149 @@
+package xyz.quaver.pupil.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val md_theme_light_primary = Color(0xFF006688)
+val md_theme_light_onPrimary = Color(0xFFFFFFFF)
+val md_theme_light_primaryContainer = Color(0xFFC2E8FF)
+val md_theme_light_onPrimaryContainer = Color(0xFF001E2B)
+val md_theme_light_secondary = Color(0xFF4E616D)
+val md_theme_light_onSecondary = Color(0xFFFFFFFF)
+val md_theme_light_secondaryContainer = Color(0xFFD1E5F3)
+val md_theme_light_onSecondaryContainer = Color(0xFF091E28)
+val md_theme_light_tertiary = Color(0xFF5F5A7D)
+val md_theme_light_onTertiary = Color(0xFFFFFFFF)
+val md_theme_light_tertiaryContainer = Color(0xFFE5DEFF)
+val md_theme_light_onTertiaryContainer = Color(0xFF1C1736)
+val md_theme_light_error = Color(0xFFBA1A1A)
+val md_theme_light_errorContainer = Color(0xFFFFDAD6)
+val md_theme_light_onError = Color(0xFFFFFFFF)
+val md_theme_light_onErrorContainer = Color(0xFF410002)
+val md_theme_light_background = Color(0xFFFBFCFE)
+val md_theme_light_onBackground = Color(0xFF191C1E)
+val md_theme_light_surface = Color(0xFFFBFCFE)
+val md_theme_light_onSurface = Color(0xFF191C1E)
+val md_theme_light_surfaceVariant = Color(0xFFDCE3E9)
+val md_theme_light_onSurfaceVariant = Color(0xFF40484D)
+val md_theme_light_outline = Color(0xFF71787D)
+val md_theme_light_inverseOnSurface = Color(0xFFF0F1F3)
+val md_theme_light_inverseSurface = Color(0xFF2E3133)
+val md_theme_light_inversePrimary = Color(0xFF75D1FF)
+val md_theme_light_shadow = Color(0xFF000000)
+val md_theme_light_surfaceTint = Color(0xFF006688)
+val md_theme_light_outlineVariant = Color(0xFFC0C7CD)
+val md_theme_light_scrim = Color(0xFF000000)
+
+val md_theme_dark_primary = Color(0xFF75D1FF)
+val md_theme_dark_onPrimary = Color(0xFF003548)
+val md_theme_dark_primaryContainer = Color(0xFF004D67)
+val md_theme_dark_onPrimaryContainer = Color(0xFFC2E8FF)
+val md_theme_dark_secondary = Color(0xFFB5C9D7)
+val md_theme_dark_onSecondary = Color(0xFF20333D)
+val md_theme_dark_secondaryContainer = Color(0xFF364954)
+val md_theme_dark_onSecondaryContainer = Color(0xFFD1E5F3)
+val md_theme_dark_tertiary = Color(0xFFC9C2EA)
+val md_theme_dark_onTertiary = Color(0xFF312C4C)
+val md_theme_dark_tertiaryContainer = Color(0xFF474364)
+val md_theme_dark_onTertiaryContainer = Color(0xFFE5DEFF)
+val md_theme_dark_error = Color(0xFFFFB4AB)
+val md_theme_dark_errorContainer = Color(0xFF93000A)
+val md_theme_dark_onError = Color(0xFF690005)
+val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
+val md_theme_dark_background = Color(0xFF191C1E)
+val md_theme_dark_onBackground = Color(0xFFE1E2E5)
+val md_theme_dark_surface = Color(0xFF191C1E)
+val md_theme_dark_onSurface = Color(0xFFE1E2E5)
+val md_theme_dark_surfaceVariant = Color(0xFF40484D)
+val md_theme_dark_onSurfaceVariant = Color(0xFFC0C7CD)
+val md_theme_dark_outline = Color(0xFF8A9297)
+val md_theme_dark_inverseOnSurface = Color(0xFF191C1E)
+val md_theme_dark_inverseSurface = Color(0xFFE1E2E5)
+val md_theme_dark_inversePrimary = Color(0xFF006688)
+val md_theme_dark_shadow = Color(0xFF000000)
+val md_theme_dark_surfaceTint = Color(0xFF75D1FF)
+val md_theme_dark_outlineVariant = Color(0xFF40484D)
+val md_theme_dark_scrim = Color(0xFF000000)
+
+
+val seed = Color(0xFF4FC3F7)
+
+val Gray50 = Color(0xFFF9FAFB)
+val Gray100 = Color(0xFFF3F4F6)
+val Gray200 = Color(0xFFE5E7EB)
+val Gray300 = Color(0xFFD1D5DB)
+val Gray400 = Color(0xFF9CA3AF)
+val Gray500 = Color(0xFF6B7280)
+val Gray600 = Color(0xFF4B5563)
+val Gray700 = Color(0xFF374151)
+val Gray800 = Color(0xFF1F2937)
+val Gray900 = Color(0xFF111827)
+val Red50 = Color(0xFFFEF2F2)
+val Red100 = Color(0xFFFEE2E2)
+val Red200 = Color(0xFFFECACA)
+val Red300 = Color(0xFFFCA5A5)
+val Red400 = Color(0xFFF87171)
+val Red500 = Color(0xFFEF4444)
+val Red600 = Color(0xFFDC2626)
+val Red700 = Color(0xFFB91C1C)
+val Red800 = Color(0xFF991B1B)
+val Red900 = Color(0xFF7F1D1D)
+val Yellow50 = Color(0xFFFFFBEB)
+val Yellow100 = Color(0xFFFEF3C7)
+val Yellow200 = Color(0xFFFDE68A)
+val Yellow300 = Color(0xFFFCD34D)
+val Yellow400 = Color(0xFFFBBF24)
+val Yellow500 = Color(0xFFF59E0B)
+val Yellow600 = Color(0xFFD97706)
+val Yellow700 = Color(0xFFB45309)
+val Yellow800 = Color(0xFF92400E)
+val Yellow900 = Color(0xFF78350F)
+val Green50 = Color(0xFFECFDF5)
+val Green100 = Color(0xFFD1FAE5)
+val Green200 = Color(0xFFA7F3D0)
+val Green300 = Color(0xFF6EE7B7)
+val Green400 = Color(0xFF34D399)
+val Green500 = Color(0xFF10B981)
+val Green600 = Color(0xFF059669)
+val Green700 = Color(0xFF047857)
+val Green800 = Color(0xFF065F46)
+val Green900 = Color(0xFF064E3B)
+val Blue50 = Color(0xFFEFF6FF)
+val Blue100 = Color(0xFFDBEAFE)
+val Blue200 = Color(0xFFBFDBFE)
+val Blue300 = Color(0xFF93C5FD)
+val Blue400 = Color(0xFF60A5FA)
+val Blue500 = Color(0xFF3B82F6)
+val Blue600 = Color(0xFF2563EB)
+val Blue700 = Color(0xFF1D4ED8)
+val Blue800 = Color(0xFF1E40AF)
+val Blue900 = Color(0xFF1E3A8A)
+val Indigo50 = Color(0xFFEEF2FF)
+val Indigo100 = Color(0xFFE0E7FF)
+val Indigo200 = Color(0xFFC7D2FE)
+val Indigo300 = Color(0xFFA5B4FC)
+val Indigo400 = Color(0xFF818CF8)
+val Indigo500 = Color(0xFF6366F1)
+val Indigo600 = Color(0xFF4F46E5)
+val Indigo700 = Color(0xFF4338CA)
+val Indigo800 = Color(0xFF3730A3)
+val Indigo900 = Color(0xFF312E81)
+val Purple50 = Color(0xFFF5F3FF)
+val Purple100 = Color(0xFFEDE9FE)
+val Purple200 = Color(0xFFDDD6FE)
+val Purple300 = Color(0xFFC4B5FD)
+val Purple400 = Color(0xFFA78BFA)
+val Purple500 = Color(0xFF8B5CF6)
+val Purple600 = Color(0xFF7C3AED)
+val Purple700 = Color(0xFF6D28D9)
+val Purple800 = Color(0xFF5B21B6)
+val Purple900 = Color(0xFF4C1D95)
+val Pink50 = Color(0xFFFDF2F8)
+val Pink100 = Color(0xFFFCE7F3)
+val Pink200 = Color(0xFFFBCFE8)
+val Pink300 = Color(0xFFF9A8D4)
+val Pink400 = Color(0xFFF472B6)
+val Pink500 = Color(0xFFEC4899)
+val Pink600 = Color(0xFFDB2777)
+val Pink700 = Color(0xFFBE185D)
+val Pink800 = Color(0xFF9D174D)
+val Pink900 = Color(0xFF831843)
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/theme/Theme.kt b/app/src/main/java/xyz/quaver/pupil/ui/theme/Theme.kt
new file mode 100644
index 00000000..c2d38f1d
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/theme/Theme.kt
@@ -0,0 +1,97 @@
+package xyz.quaver.pupil.ui.theme
+
+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 LightColors = lightColorScheme(
+ primary = md_theme_light_primary,
+ onPrimary = md_theme_light_onPrimary,
+ primaryContainer = md_theme_light_primaryContainer,
+ onPrimaryContainer = md_theme_light_onPrimaryContainer,
+ secondary = md_theme_light_secondary,
+ onSecondary = md_theme_light_onSecondary,
+ secondaryContainer = md_theme_light_secondaryContainer,
+ onSecondaryContainer = md_theme_light_onSecondaryContainer,
+ tertiary = md_theme_light_tertiary,
+ onTertiary = md_theme_light_onTertiary,
+ tertiaryContainer = md_theme_light_tertiaryContainer,
+ onTertiaryContainer = md_theme_light_onTertiaryContainer,
+ error = md_theme_light_error,
+ errorContainer = md_theme_light_errorContainer,
+ onError = md_theme_light_onError,
+ onErrorContainer = md_theme_light_onErrorContainer,
+ background = md_theme_light_background,
+ onBackground = md_theme_light_onBackground,
+ surface = md_theme_light_surface,
+ onSurface = md_theme_light_onSurface,
+ surfaceVariant = md_theme_light_surfaceVariant,
+ onSurfaceVariant = md_theme_light_onSurfaceVariant,
+ outline = md_theme_light_outline,
+ inverseOnSurface = md_theme_light_inverseOnSurface,
+ inverseSurface = md_theme_light_inverseSurface,
+ inversePrimary = md_theme_light_inversePrimary,
+ surfaceTint = md_theme_light_surfaceTint,
+ outlineVariant = md_theme_light_outlineVariant,
+ scrim = md_theme_light_scrim,
+)
+
+
+private val DarkColors = darkColorScheme(
+ primary = md_theme_dark_primary,
+ onPrimary = md_theme_dark_onPrimary,
+ primaryContainer = md_theme_dark_primaryContainer,
+ onPrimaryContainer = md_theme_dark_onPrimaryContainer,
+ secondary = md_theme_dark_secondary,
+ onSecondary = md_theme_dark_onSecondary,
+ secondaryContainer = md_theme_dark_secondaryContainer,
+ onSecondaryContainer = md_theme_dark_onSecondaryContainer,
+ tertiary = md_theme_dark_tertiary,
+ onTertiary = md_theme_dark_onTertiary,
+ tertiaryContainer = md_theme_dark_tertiaryContainer,
+ onTertiaryContainer = md_theme_dark_onTertiaryContainer,
+ error = md_theme_dark_error,
+ errorContainer = md_theme_dark_errorContainer,
+ onError = md_theme_dark_onError,
+ onErrorContainer = md_theme_dark_onErrorContainer,
+ background = md_theme_dark_background,
+ onBackground = md_theme_dark_onBackground,
+ surface = md_theme_dark_surface,
+ onSurface = md_theme_dark_onSurface,
+ surfaceVariant = md_theme_dark_surfaceVariant,
+ onSurfaceVariant = md_theme_dark_onSurfaceVariant,
+ outline = md_theme_dark_outline,
+ inverseOnSurface = md_theme_dark_inverseOnSurface,
+ inverseSurface = md_theme_dark_inverseSurface,
+ inversePrimary = md_theme_dark_inversePrimary,
+ surfaceTint = md_theme_dark_surfaceTint,
+ outlineVariant = md_theme_dark_outlineVariant,
+ scrim = md_theme_dark_scrim,
+)
+
+@Composable
+fun AppTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ content: @Composable() () -> Unit,
+) {
+ val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
+
+ val colors = when {
+ dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current)
+ dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
+ darkTheme -> DarkColors
+ else -> LightColors
+ }
+
+ MaterialTheme(
+ colorScheme = colors,
+ content = content
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/MainViewModel.kt b/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/MainViewModel.kt
new file mode 100644
index 00000000..7e44d786
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/viewmodel/MainViewModel.kt
@@ -0,0 +1,12 @@
+package xyz.quaver.pupil.ui.viewmodel
+
+import androidx.lifecycle.ViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class MainViewModel : ViewModel() {
+ private val _uiState = MutableStateFlow(SearchState())
+ val searchState: StateFlow = _uiState
+}
+
+data class SearchState(val stub: String = "")
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/util/misc.kt b/app/src/main/java/xyz/quaver/pupil/util/misc.kt
index 327ba3f8..2ab7a2f2 100644
--- a/app/src/main/java/xyz/quaver/pupil/util/misc.kt
+++ b/app/src/main/java/xyz/quaver/pupil/util/misc.kt
@@ -24,24 +24,26 @@ import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
-import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.firebase.crashlytics.FirebaseCrashlytics
-import kotlinx.serialization.json.*
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.contentOrNull
+import kotlinx.serialization.json.jsonArray
+import kotlinx.serialization.json.jsonObject
+import kotlinx.serialization.json.jsonPrimitive
import okhttp3.OkHttpClient
import okhttp3.Request
import xyz.quaver.pupil.R
import xyz.quaver.pupil.hitomi.GalleryBlock
import xyz.quaver.pupil.hitomi.GalleryInfo
import xyz.quaver.pupil.hitomi.imageUrlFromImage
-import java.util.*
-import kotlin.collections.ArrayList
+import java.util.Locale
@OptIn(ExperimentalStdlibApi::class)
-fun String.wordCapitalize() : String {
+fun String.wordCapitalize(): String {
val result = ArrayList()
@SuppressLint("DefaultLocale")
@@ -59,8 +61,9 @@ private val suffix = listOf(
"TB" //really?
)
-fun byteToString(byte: Long, precision : Int = 1) : String {
- var size = byte.toDouble(); var suffixIndex = 0
+fun byteToString(byte: Long, precision: Int = 1): String {
+ var size = byte.toDouble()
+ var suffixIndex = 0
while (size >= 1024) {
size /= 1024
@@ -92,6 +95,7 @@ val formatMap = mapOf (String)>(
"-group-" to { if (groups.isNotEmpty()) groups.joinToString() else "N/A" }
// TODO
)
+
/**
* Formats download folder name with given Metadata
*/
@@ -117,20 +121,20 @@ suspend fun GalleryInfo.getRequestBuilders(): List {
runCatching {
imageUrlFromImage(galleryID, it, false)
}
- .onFailure {
- FirebaseCrashlytics.getInstance().recordException(it)
- }
- .getOrDefault("https://a/")
+ .onFailure {
+ FirebaseCrashlytics.getInstance().recordException(it)
+ }
+ .getOrDefault("https://a/")
)
.header("Referer", "https://hitomi.la/")
}
}
fun byteCount(codePoint: Int): Int = when (codePoint) {
- in 0 ..< 0x80 -> 1
- in 0x80 ..< 0x800 -> 2
- in 0x800 ..< 0x10000 -> 3
- in 0x10000 ..< 0x110000 -> 4
+ in 0..<0x80 -> 1
+ in 0x80..<0x800 -> 2
+ in 0x800..<0x10000 -> 3
+ in 0x10000..<0x110000 -> 4
else -> 0
}
@@ -168,7 +172,10 @@ val JsonElement.content
fun checkNotificationEnabled(context: Context) =
Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU ||
- ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
+ ContextCompat.checkSelfPermission(
+ context,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) == PackageManager.PERMISSION_GRANTED
fun showNotificationPermissionExplanationDialog(context: Context) {
AlertDialog.Builder(context)
@@ -182,12 +189,16 @@ fun requestNotificationPermission(
activity: Activity,
requestPermissionLauncher: ActivityResultLauncher,
showRationale: Boolean = true,
- ifGranted: () -> Unit,
+ ifGranted: () -> Unit = { },
) {
when {
checkNotificationEnabled(activity) -> ifGranted()
- showRationale && ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.POST_NOTIFICATIONS) ->
+ showRationale && ActivityCompat.shouldShowRequestPermissionRationale(
+ activity,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) ->
showNotificationPermissionExplanationDialog(activity)
+
else ->
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 39728430..b4c8c6dc 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -46,6 +46,7 @@ runner = "1.6.2"
skyfishjyLibrary = "1.0.1"
dotsindicator = "5.1.0"
workRuntimeKtx = "2.10.0"
+material3WindowSizeClassAndroid = "1.3.1"
[libraries]
activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" }
@@ -114,6 +115,9 @@ compose-adaptive = { module = "androidx.compose.material3.adaptive:adaptive" }
compose-activity = { module = "androidx.activity:activity-compose", version = "1.10.1" }
compose-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version = "2.8.7" }
compose-livedata = { module = "androidx.compose.runtime:runtime-livedata" }
+compose-navigation = { module = "androidx.navigation:navigation-compose", version = "2.8.8" }
+
+accompanist-adaptive = { module = "com.google.accompanist:accompanist-adaptive", version = "0.37.2" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }