hello world
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -5,22 +5,34 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="23"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="23"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="23" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="23" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation"
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission
|
||||
android:name="android.permission.NEARBY_WIFI_DEVICES"
|
||||
android:usesPermissionFlags="neverForLocation"
|
||||
tools:targetApi="s" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="32"
|
||||
<uses-permission
|
||||
android:name="android.permission.ACCESS_FINE_LOCATION"
|
||||
android:maxSdkVersion="32"
|
||||
tools:ignore="CoarseFineLocation" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera.autofocus"
|
||||
android:required="false" />
|
||||
|
||||
<application
|
||||
android:name=".Pupil"
|
||||
@@ -28,20 +40,20 @@
|
||||
android:fullBackupContent="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
tools:replace="android:theme"
|
||||
tools:ignore="UnusedAttribute">
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:replace="android:theme">
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||
android:value="face" />
|
||||
|
||||
<provider
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
|
||||
@@ -51,15 +63,18 @@
|
||||
|
||||
</provider>
|
||||
|
||||
<service android:name=".services.DownloadService"
|
||||
<service
|
||||
android:name=".services.DownloadService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
|
||||
<service android:name=".services.TransferClientService"
|
||||
<service
|
||||
android:name=".services.TransferClientService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
|
||||
<service android:name=".services.TransferServerService"
|
||||
<service
|
||||
android:name=".services.TransferServerService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
|
||||
@@ -75,8 +90,8 @@
|
||||
<activity
|
||||
android:name=".ui.ReaderActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:parentActivityName=".ui.MainActivity"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:parentActivityName=".ui.MainComposeActivity">
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
@@ -85,8 +100,8 @@
|
||||
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:host="*.hasha.in"/>
|
||||
<data android:pathPrefix="/reader"/>
|
||||
<data android:host="*.hasha.in" />
|
||||
<data android:pathPrefix="/reader" />
|
||||
</intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
@@ -96,8 +111,8 @@
|
||||
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:host="hitomi.la"/>
|
||||
<data android:pathPrefix="/galleries"/>
|
||||
<data android:host="hitomi.la" />
|
||||
<data android:pathPrefix="/galleries" />
|
||||
</intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
@@ -177,13 +192,13 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.SettingsActivity"
|
||||
android:label="@string/settings_title">
|
||||
</activity>
|
||||
android:label="@string/settings_title" />
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
android:name=".ui.MainComposeActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:theme="@style/NoActionBarAppTheme"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:theme="@android:style/Theme.Material.Light.NoActionBar"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
@@ -191,7 +206,6 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="net.rdrei.android.dirchooser.DirectoryChooserActivity" />
|
||||
<activity android:name=".ui.TransferActivity" />
|
||||
</application>
|
||||
|
||||
|
||||
@@ -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 ->
|
||||
defaultTrustManagerFactory.trustManagers.filterIsInstance<X509TrustManager>()
|
||||
.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")
|
||||
@@ -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,35 +215,60 @@ 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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
manager.createNotificationChannel(
|
||||
NotificationChannel(
|
||||
"transfer",
|
||||
getString(R.string.channel_transfer),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
description = getString(R.string.channel_transfer_description)
|
||||
enableLights(false)
|
||||
enableVibration(false)
|
||||
@@ -245,10 +276,12 @@ class Pupil : Application() {
|
||||
})
|
||||
}
|
||||
|
||||
AppCompatDelegate.setDefaultNightMode(when (Preferences.get<Boolean>("dark_mode")) {
|
||||
AppCompatDelegate.setDefaultNightMode(
|
||||
when (Preferences.get<Boolean>("dark_mode")) {
|
||||
true -> AppCompatDelegate.MODE_NIGHT_YES
|
||||
false -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
super.onCreate()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
44
app/src/main/java/xyz/quaver/pupil/ui/MainComposeActivity.kt
Normal file
44
app/src/main/java/xyz/quaver/pupil/ui/MainComposeActivity.kt
Normal file
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
app/src/main/java/xyz/quaver/pupil/ui/compose/MainApp.kt
Normal file
20
app/src/main/java/xyz/quaver/pupil/ui/compose/MainApp.kt
Normal file
@@ -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<DisplayFeature>,
|
||||
navController: NavController = rememberNavController(),
|
||||
windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass,
|
||||
) {
|
||||
Text("Hello, World!")
|
||||
}
|
||||
149
app/src/main/java/xyz/quaver/pupil/ui/theme/Color.kt
Normal file
149
app/src/main/java/xyz/quaver/pupil/ui/theme/Color.kt
Normal file
@@ -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)
|
||||
97
app/src/main/java/xyz/quaver/pupil/ui/theme/Theme.kt
Normal file
97
app/src/main/java/xyz/quaver/pupil/ui/theme/Theme.kt
Normal file
@@ -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
|
||||
)
|
||||
}
|
||||
@@ -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<SearchState> = _uiState
|
||||
}
|
||||
|
||||
data class SearchState(val stub: String = "")
|
||||
@@ -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<String>()
|
||||
|
||||
@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, GalleryBlock.() -> (String)>(
|
||||
"-group-" to { if (groups.isNotEmpty()) groups.joinToString() else "N/A" }
|
||||
// TODO
|
||||
)
|
||||
|
||||
/**
|
||||
* Formats download folder name with given Metadata
|
||||
*/
|
||||
@@ -127,10 +131,10 @@ suspend fun GalleryInfo.getRequestBuilders(): List<Request.Builder> {
|
||||
}
|
||||
|
||||
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<String>,
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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" }
|
||||
|
||||
Reference in New Issue
Block a user