├── composeApp
├── libs
│ └── common
│ │ └── data.txt
├── src
│ ├── androidMain
│ │ ├── res
│ │ │ ├── values
│ │ │ │ └── strings.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── logo_pro.webp
│ │ │ │ ├── logo_pro_round.webp
│ │ │ │ └── logo_pro_foreground.webp
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── logo_pro.webp
│ │ │ │ ├── logo_pro_round.webp
│ │ │ │ └── logo_pro_foreground.webp
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── logo_pro.webp
│ │ │ │ ├── logo_pro_round.webp
│ │ │ │ └── logo_pro_foreground.webp
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── logo_pro.webp
│ │ │ │ ├── logo_pro_round.webp
│ │ │ │ └── logo_pro_foreground.webp
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── logo_pro.webp
│ │ │ │ ├── logo_pro_round.webp
│ │ │ │ └── logo_pro_foreground.webp
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── logo_pro.xml
│ │ │ │ └── logo_pro_round.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── logo_pro_background.xml
│ │ ├── logo_pro-playstore.png
│ │ ├── kotlin
│ │ │ ├── di
│ │ │ │ └── CommonModule.android.kt
│ │ │ ├── ui
│ │ │ │ └── components
│ │ │ │ │ ├── MediaPlayer.android.kt
│ │ │ │ │ └── Notification.android.kt
│ │ │ ├── data
│ │ │ │ └── store
│ │ │ │ │ └── SettingsWrapper.android.kt
│ │ │ ├── biz
│ │ │ │ ├── MainUtils.android.kt
│ │ │ │ ├── StatusBar.android.kt
│ │ │ │ ├── FMessagingService.android.kt
│ │ │ │ └── ChatSocketService.android.kt
│ │ │ └── com
│ │ │ │ └── aster
│ │ │ │ └── yuno
│ │ │ │ └── tomoyo
│ │ │ │ └── MainActivity.kt
│ │ └── AndroidManifest.xml
│ ├── desktopMain
│ │ ├── resources
│ │ │ ├── empty.png
│ │ │ ├── logo_pro.ico
│ │ │ ├── logo_pro_round.png
│ │ │ └── logo_pro_round_32.png
│ │ └── kotlin
│ │ │ ├── biz
│ │ │ ├── StatusBar.desktop.kt
│ │ │ ├── MainUtils.desktop.kt
│ │ │ └── AudioPlayer.desktop.kt
│ │ │ ├── ui
│ │ │ └── components
│ │ │ │ ├── MediaPlayer.desktop.kt
│ │ │ │ ├── Notification.desktop.kt
│ │ │ │ └── StartLoading.kt
│ │ │ ├── data
│ │ │ └── store
│ │ │ │ └── SettingsWrapper.desktop.kt
│ │ │ ├── di
│ │ │ └── CommonModule.desktop.kt
│ │ │ └── main.kt
│ ├── commonMain
│ │ ├── composeResources
│ │ │ ├── drawable
│ │ │ │ ├── bg1.jpg
│ │ │ │ ├── bg3.jpg
│ │ │ │ ├── logo_pro_round_512.png
│ │ │ │ ├── logo_pro_trans_128.png
│ │ │ │ ├── user_solid.xml
│ │ │ │ ├── input_exclamation_circle.xml
│ │ │ │ ├── input_check_circle.xml
│ │ │ │ ├── media_circle_pause.xml
│ │ │ │ ├── id_badge_solid.xml
│ │ │ │ ├── envelope_alt.xml
│ │ │ │ ├── input_microphone.xml
│ │ │ │ ├── input_map_pin.xml
│ │ │ │ ├── skull_solid.xml
│ │ │ │ ├── media_repeat_all.xml
│ │ │ │ ├── input_folder.xml
│ │ │ │ ├── media_circle_play.xml
│ │ │ │ ├── media_play.xml
│ │ │ │ ├── media_circle_next.xml
│ │ │ │ ├── input_plus_square.xml
│ │ │ │ ├── input_map_marker.xml
│ │ │ │ ├── input_send.xml
│ │ │ │ ├── input_question_circle.xml
│ │ │ │ ├── media_circle_previous.xml
│ │ │ │ ├── media_next.xml
│ │ │ │ ├── input_tag.xml
│ │ │ │ ├── input_sliders_h.xml
│ │ │ │ ├── media_previous.xml
│ │ │ │ ├── stackoverflow.xml
│ │ │ │ ├── drumstick_bite_solid.xml
│ │ │ │ ├── input_upload.xml
│ │ │ │ ├── media_audio.xml
│ │ │ │ ├── input_compass.xml
│ │ │ │ ├── input_film.xml
│ │ │ │ ├── twitter.xml
│ │ │ │ ├── input_heart.xml
│ │ │ │ ├── media_pause.xml
│ │ │ │ ├── media_circle_stop.xml
│ │ │ │ ├── input_user.xml
│ │ │ │ ├── user_graduate_solid.xml
│ │ │ │ ├── input_link.xml
│ │ │ │ ├── input_image.xml
│ │ │ │ ├── media_repeat_one.xml
│ │ │ │ ├── input_camera.xml
│ │ │ │ ├── envelope_question.xml
│ │ │ │ ├── envelope_heart.xml
│ │ │ │ ├── media_shuffle.xml
│ │ │ │ ├── github.xml
│ │ │ │ ├── input_trash.xml
│ │ │ │ ├── input_package.xml
│ │ │ │ ├── input_star.xml
│ │ │ │ ├── envelope_exclamation.xml
│ │ │ │ ├── input_map.xml
│ │ │ │ ├── google.xml
│ │ │ │ ├── input_store.xml
│ │ │ │ ├── user_secret_solid.xml
│ │ │ │ ├── input_calendar.xml
│ │ │ │ ├── envelope_star.xml
│ │ │ │ ├── input_phone.xml
│ │ │ │ ├── input_users_three.xml
│ │ │ │ ├── input_globe.xml
│ │ │ │ ├── reddit.xml
│ │ │ │ ├── amazon.xml
│ │ │ │ ├── input_settings.xml
│ │ │ │ └── compose-multiplatform.xml
│ │ │ └── font
│ │ │ │ ├── static
│ │ │ │ ├── RobotoSlab-Black.ttf
│ │ │ │ ├── RobotoSlab-Bold.ttf
│ │ │ │ ├── RobotoSlab-Light.ttf
│ │ │ │ ├── RobotoSlab-Thin.ttf
│ │ │ │ ├── RobotoSlab-Medium.ttf
│ │ │ │ ├── RobotoSlab-Regular.ttf
│ │ │ │ ├── RobotoSlab-SemiBold.ttf
│ │ │ │ ├── RobotoSlab-ExtraBold.ttf
│ │ │ │ └── RobotoSlab-ExtraLight.ttf
│ │ │ │ └── RobotoSlab-VariableFont_wght.ttf
│ │ └── kotlin
│ │ │ ├── data
│ │ │ ├── PlatformInitData.kt
│ │ │ ├── ResultObj.kt
│ │ │ ├── store
│ │ │ │ ├── SettingsWrapper.kt
│ │ │ │ └── DataStorageManager.kt
│ │ │ ├── ArticleModel.kt
│ │ │ ├── MusicModel.kt
│ │ │ ├── model
│ │ │ │ ├── ContactScreenModel.kt
│ │ │ │ ├── GlobalDataModel.kt
│ │ │ │ ├── ArticleScreenModel.kt
│ │ │ │ └── MusicScreenModel.kt
│ │ │ ├── ChatModel.kt
│ │ │ └── UserModel.kt
│ │ │ ├── ui
│ │ │ ├── components
│ │ │ │ ├── MediaPlayer.kt
│ │ │ │ ├── CardComponents.kt
│ │ │ │ └── Notification.kt
│ │ │ └── pages
│ │ │ │ └── MainVideos.kt
│ │ │ ├── biz
│ │ │ ├── StatusBar.kt
│ │ │ ├── AudioPlayer.kt
│ │ │ ├── CustomTransition.kt
│ │ │ └── MainUtils.kt
│ │ │ ├── di
│ │ │ ├── KoinInit.kt
│ │ │ └── CommonModule.kt
│ │ │ ├── theme
│ │ │ └── Type.kt
│ │ │ └── constant
│ │ │ ├── BaseConstants.kt
│ │ │ └── ChineseDateData.kt
│ └── iosMain
│ │ └── kotlin
│ │ ├── biz
│ │ ├── StatusBar.ios.kt
│ │ └── MainUtils.ios.kt
│ │ ├── ui.components
│ │ ├── Notification.ios.kt
│ │ └── MediaPlayer.ios.kt
│ │ ├── di
│ │ └── CommonModule.ios.kt
│ │ ├── data.store
│ │ └── SettingsWrapper.ios.kt
│ │ └── MainViewController.kt
├── proguard-rules.pro
├── compose-desktop.pro
├── google-services.json
└── config
│ └── compose_compiler_config.conf
├── image
├── ios_1.png
├── ios_2.png
├── ios_3.png
├── ios_4.png
├── ios_5.png
├── ios_6.png
├── ios_7.png
├── ios_8.png
├── ios_9.png
├── android_1.jpg
├── android_2.jpg
├── android_3.jpg
├── android_4.jpg
├── android_5.jpg
├── android_6.jpg
├── android_7.jpg
├── android_8.jpg
├── android_9.jpg
├── desktop_1.jpg
├── desktop_2.jpg
├── desktop_3.jpg
├── desktop_4.jpg
├── desktop_5.jpg
├── desktop_6.jpg
├── desktop_7.jpg
├── desktop_8.jpg
└── desktop_9.jpg
├── iosApp
├── Configuration
│ └── Config.xcconfig
├── iosApp
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── app-icon-512.png
│ │ │ └── Contents.json
│ │ └── AccentColor.colorset
│ │ │ └── Contents.json
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ ├── ContentView.swift
│ ├── iOSApp.swift
│ ├── GoogleService-Info.plist
│ └── Info.plist
└── iosApp.xcodeproj
│ └── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── swiftpm
│ └── Package.resolved
├── gradle
├── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
└── libs.versions.toml
├── gradle.properties
├── .gitignore
├── .fleet
└── receipt.json
├── LICENSE
├── settings.gradle.kts
├── gradlew.bat
└── README_zh.md
/composeApp/libs/common/data.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/image/ios_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/ios_1.png
--------------------------------------------------------------------------------
/image/ios_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/ios_2.png
--------------------------------------------------------------------------------
/image/ios_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/ios_3.png
--------------------------------------------------------------------------------
/image/ios_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/ios_4.png
--------------------------------------------------------------------------------
/image/ios_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/ios_5.png
--------------------------------------------------------------------------------
/image/ios_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/ios_6.png
--------------------------------------------------------------------------------
/image/ios_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/ios_7.png
--------------------------------------------------------------------------------
/image/ios_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/ios_8.png
--------------------------------------------------------------------------------
/image/ios_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/ios_9.png
--------------------------------------------------------------------------------
/image/android_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/android_1.jpg
--------------------------------------------------------------------------------
/image/android_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/android_2.jpg
--------------------------------------------------------------------------------
/image/android_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/android_3.jpg
--------------------------------------------------------------------------------
/image/android_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/android_4.jpg
--------------------------------------------------------------------------------
/image/android_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/android_5.jpg
--------------------------------------------------------------------------------
/image/android_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/android_6.jpg
--------------------------------------------------------------------------------
/image/android_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/android_7.jpg
--------------------------------------------------------------------------------
/image/android_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/android_8.jpg
--------------------------------------------------------------------------------
/image/android_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/android_9.jpg
--------------------------------------------------------------------------------
/image/desktop_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/desktop_1.jpg
--------------------------------------------------------------------------------
/image/desktop_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/desktop_2.jpg
--------------------------------------------------------------------------------
/image/desktop_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/desktop_3.jpg
--------------------------------------------------------------------------------
/image/desktop_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/desktop_4.jpg
--------------------------------------------------------------------------------
/image/desktop_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/desktop_5.jpg
--------------------------------------------------------------------------------
/image/desktop_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/desktop_6.jpg
--------------------------------------------------------------------------------
/image/desktop_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/desktop_7.jpg
--------------------------------------------------------------------------------
/image/desktop_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/desktop_8.jpg
--------------------------------------------------------------------------------
/image/desktop_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/image/desktop_9.jpg
--------------------------------------------------------------------------------
/iosApp/Configuration/Config.xcconfig:
--------------------------------------------------------------------------------
1 | TEAM_ID=
2 | BUNDLE_ID=com.aster.yuno.tomoyo.Tomoyo
3 | APP_NAME=Tomoyo
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Tomoyo
3 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
--------------------------------------------------------------------------------
/composeApp/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -dontwarn java.net.**
2 | -dontwarn org.slf4j.**
3 | -dontwarn androidx.test.platform.app.InstrumentationRegistry
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/resources/empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/desktopMain/resources/empty.png
--------------------------------------------------------------------------------
/composeApp/src/androidMain/logo_pro-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/logo_pro-playstore.png
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/resources/logo_pro.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/desktopMain/resources/logo_pro.ico
--------------------------------------------------------------------------------
/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/resources/logo_pro_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/desktopMain/resources/logo_pro_round.png
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-hdpi/logo_pro.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-hdpi/logo_pro.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-mdpi/logo_pro.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-mdpi/logo_pro.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xhdpi/logo_pro.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-xhdpi/logo_pro.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxhdpi/logo_pro.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-xxhdpi/logo_pro.webp
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/resources/logo_pro_round_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/desktopMain/resources/logo_pro_round_32.png
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxxhdpi/logo_pro.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-xxxhdpi/logo_pro.webp
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/bg1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/drawable/bg1.jpg
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/bg3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/drawable/bg3.jpg
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-hdpi/logo_pro_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-hdpi/logo_pro_round.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-mdpi/logo_pro_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-mdpi/logo_pro_round.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xhdpi/logo_pro_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-xhdpi/logo_pro_round.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxhdpi/logo_pro_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-xxhdpi/logo_pro_round.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxxhdpi/logo_pro_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-xxxhdpi/logo_pro_round.webp
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-512.png
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-hdpi/logo_pro_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-hdpi/logo_pro_foreground.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-mdpi/logo_pro_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-mdpi/logo_pro_foreground.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xhdpi/logo_pro_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-xhdpi/logo_pro_foreground.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxhdpi/logo_pro_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-xxhdpi/logo_pro_foreground.webp
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-xxxhdpi/logo_pro_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/androidMain/res/mipmap-xxxhdpi/logo_pro_foreground.webp
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/logo_pro_round_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/drawable/logo_pro_round_512.png
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/logo_pro_trans_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/drawable/logo_pro_trans_128.png
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Black.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Bold.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Light.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Thin.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Medium.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-Regular.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-SemiBold.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/RobotoSlab-VariableFont_wght.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/RobotoSlab-VariableFont_wght.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-ExtraBold.ttf
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-ExtraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AsterCass/Tomoyo/HEAD/composeApp/src/commonMain/composeResources/font/static/RobotoSlab-ExtraLight.ttf
--------------------------------------------------------------------------------
/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/PlatformInitData.kt:
--------------------------------------------------------------------------------
1 | package data
2 |
3 | import constant.enums.MainNavigationEnum
4 |
5 | data class PlatformInitData(
6 | val extraNavigationList: List = emptyList(),
7 | )
8 |
9 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/ui/components/MediaPlayer.kt:
--------------------------------------------------------------------------------
1 | package ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.Modifier
5 |
6 |
7 | @Composable
8 | expect fun MediaPlayer(modifier: Modifier, url: String)
--------------------------------------------------------------------------------
/composeApp/compose-desktop.pro:
--------------------------------------------------------------------------------
1 | -dontwarn cn.hutool.core.util.*
2 | -dontwarn okhttp3.internal.platform.*
3 | -dontwarn androidx.datastore.preferences.protobuf.*
4 | -dontwarn okhttp3.internal.platform.android.*
5 | -dontwarn io.ktor.network.sockets.*
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/ResultObj.kt:
--------------------------------------------------------------------------------
1 | package data
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | class ResultObj(
7 | var status: Int,
8 | var message: String? = null,
9 | var data: T? = null,
10 | )
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/store/SettingsWrapper.kt:
--------------------------------------------------------------------------------
1 | package data.store
2 |
3 | import com.russhwolf.settings.ExperimentalSettingsApi
4 | import com.russhwolf.settings.coroutines.FlowSettings
5 |
6 | expect class SettingsWrapper {
7 | @OptIn(ExperimentalSettingsApi::class)
8 | fun createSettings(): FlowSettings
9 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-anydpi-v26/logo_pro.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/mipmap-anydpi-v26/logo_pro_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "app-icon-512.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "512x512"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 |
3 | #Gradle
4 | org.gradle.jvmargs=-Xmx4608m -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
5 |
6 | #Android
7 | android.suppressUnsupportedCompileSdk=35
8 | android.nonTransitiveRClass=true
9 | android.useAndroidX=true
10 |
11 | # ignore
12 | kotlin.native.ignoreDisabledTargets=true
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/biz/StatusBar.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.graphics.Color
5 |
6 | expect class StatusBar() {
7 |
8 | @Composable
9 | fun UpdateColor(
10 | statusBarColor: Color,
11 | navigationBarColor: Color,
12 | isLight: Boolean,
13 | )
14 |
15 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | #distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
4 | distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.7-bin.zip
5 | networkTimeout=10000
6 | validateDistributionUrl=true
7 | zipStoreBase=GRADLE_USER_HOME
8 | zipStorePath=wrapper/dists
9 |
--------------------------------------------------------------------------------
/composeApp/src/iosMain/kotlin/biz/StatusBar.ios.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.graphics.Color
5 |
6 | actual class StatusBar actual constructor() {
7 | @Composable
8 | actual fun UpdateColor(
9 | statusBarColor: Color,
10 | navigationBarColor: Color,
11 | isLight: Boolean,
12 | ) {
13 | }
14 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .kotlin
3 | .gradle
4 | **/build/
5 | xcuserdata
6 | !src/**/build/
7 | local.properties
8 | .idea
9 | .DS_Store
10 | captures
11 | .externalNativeBuild
12 | .cxx
13 | *.xcodeproj/*
14 | !*.xcodeproj/project.pbxproj
15 | !*.xcodeproj/xcshareddata/
16 | !*.xcodeproj/project.xcworkspace/
17 | !*.xcworkspace/contents.xcworkspacedata
18 | **/xcshareddata/WorkspaceSettings.xcsettings
19 |
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/kotlin/biz/StatusBar.desktop.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.graphics.Color
5 |
6 | actual class StatusBar actual constructor() {
7 | @Composable
8 | actual fun UpdateColor(
9 | statusBarColor: Color,
10 | navigationBarColor: Color,
11 | isLight: Boolean,
12 | ) {
13 | }
14 | }
--------------------------------------------------------------------------------
/composeApp/src/iosMain/kotlin/ui.components/Notification.ios.kt:
--------------------------------------------------------------------------------
1 | package ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 |
5 |
6 | actual fun sendAppNotification(title: String, content: String) {
7 |
8 | }
9 |
10 | @Composable
11 | actual fun CheckAppNotificationPermission(
12 | requestPermission: @Composable (() -> Unit) -> Unit
13 | ) {
14 | }
15 |
16 | actual fun clearAppNotification() {
17 |
18 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/biz/AudioPlayer.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import data.AudioSimpleModel
4 | import data.MusicPlayerState
5 |
6 | expect class AudioPlayer(musicPlayerState: MusicPlayerState) {
7 | fun start(id: String)
8 | fun play()
9 | fun pause()
10 | fun next()
11 | fun prev()
12 | fun seekTo(time: Double)
13 | fun cleanUp()
14 |
15 | fun clearSongs()
16 | fun addSongList(songs: Map)
17 | }
--------------------------------------------------------------------------------
/.fleet/receipt.json:
--------------------------------------------------------------------------------
1 | // Project generated by Kotlin Multiplatform Wizard
2 | {
3 | "spec": {
4 | "template_id": "kmt",
5 | "targets": {
6 | "android": {
7 | "ui": [
8 | "compose"
9 | ]
10 | },
11 | "desktop": {
12 | "ui": [
13 | "compose"
14 | ]
15 | }
16 | }
17 | },
18 | "timestamp": "2024-07-02T05:38:41.891342060Z"
19 | }
--------------------------------------------------------------------------------
/composeApp/src/iosMain/kotlin/ui.components/MediaPlayer.ios.kt:
--------------------------------------------------------------------------------
1 | package ui.components
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 |
8 | @Composable
9 | actual fun MediaPlayer(modifier: Modifier, url: String) {
10 |
11 | Column {
12 | Text("目前版本对于JavaFx以及vlcj、包括Swing的支持都很差,windows端暂时不支持视频播放")
13 | Text("")
14 | }
15 |
16 | }
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/kotlin/ui/components/MediaPlayer.desktop.kt:
--------------------------------------------------------------------------------
1 | package ui.components
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 |
8 | @Composable
9 | actual fun MediaPlayer(modifier: Modifier, url: String) {
10 |
11 | Column {
12 | Text("目前版本对于JavaFx以及vlcj、包括Swing的支持都很差,windows端暂时不支持视频播放")
13 | Text("")
14 | }
15 |
16 | }
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/composeApp/src/iosMain/kotlin/di/CommonModule.ios.kt:
--------------------------------------------------------------------------------
1 | package di
2 |
3 |
4 | import com.russhwolf.settings.ExperimentalSettingsApi
5 | import data.store.SettingsWrapper
6 | import org.koin.core.module.Module
7 | import org.koin.core.qualifier.named
8 | import org.koin.dsl.module
9 |
10 |
11 | @OptIn(ExperimentalSettingsApi::class)
12 | actual fun platformModule(): Module = module {
13 |
14 | single { SettingsWrapper().createSettings() }
15 |
16 | single(qualifier = named("isMobile")) {
17 | true
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/user_solid.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/di/CommonModule.android.kt:
--------------------------------------------------------------------------------
1 | package di
2 |
3 |
4 | import com.russhwolf.settings.ExperimentalSettingsApi
5 | import data.store.SettingsWrapper
6 | import org.koin.core.module.Module
7 | import org.koin.core.qualifier.named
8 | import org.koin.dsl.module
9 |
10 | @OptIn(ExperimentalSettingsApi::class)
11 | actual fun platformModule(): Module = module {
12 | single {
13 | SettingsWrapper().createSettings()
14 | }
15 |
16 | single(qualifier = named("isMobile")) {
17 | true
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/di/KoinInit.kt:
--------------------------------------------------------------------------------
1 | package di
2 |
3 | import org.koin.core.Koin
4 | import org.koin.core.context.startKoin
5 |
6 | import org.koin.dsl.KoinAppDeclaration
7 |
8 | class KoinInit {
9 | fun init(appDeclaration: KoinAppDeclaration = {}): Koin {
10 | return startKoin {
11 | modules(
12 | listOf(
13 | commonModule(),
14 | platformModule(),
15 | ),
16 | )
17 | appDeclaration()
18 | }.koin
19 | }
20 |
21 |
22 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/ContentView.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import SwiftUI
3 | import ComposeApp
4 |
5 | struct ComposeView: UIViewControllerRepresentable {
6 | func makeUIViewController(context: Context) -> UIViewController {
7 | MainViewControllerKt.MainViewController()
8 | }
9 |
10 | func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
11 | }
12 |
13 | struct ContentView: View {
14 | var body: some View {
15 | ComposeView()
16 | .ignoresSafeArea(.keyboard) // Compose has own keyboard handler
17 | }
18 | }
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_exclamation_circle.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_check_circle.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/iosApp/iosApp/iOSApp.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import FirebaseCore
3 |
4 |
5 | class AppDelegate: NSObject, UIApplicationDelegate {
6 | func application(_ application: UIApplication,
7 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
8 | // FirebaseApp.configure()
9 |
10 | return true
11 | }
12 | }
13 |
14 | @main
15 | struct iOSApp: App {
16 |
17 | @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
18 |
19 | var body: some Scene {
20 | WindowGroup {
21 | ContentView()
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/kotlin/data/store/SettingsWrapper.desktop.kt:
--------------------------------------------------------------------------------
1 | package data.store
2 |
3 | import com.russhwolf.settings.ExperimentalSettingsApi
4 | import com.russhwolf.settings.PreferencesSettings
5 | import com.russhwolf.settings.coroutines.FlowSettings
6 | import com.russhwolf.settings.coroutines.toFlowSettings
7 | import java.util.prefs.Preferences
8 |
9 | actual class SettingsWrapper {
10 | @OptIn(ExperimentalSettingsApi::class)
11 | actual fun createSettings(): FlowSettings {
12 | val delegate: Preferences = Preferences.userRoot()
13 | return PreferencesSettings(delegate).toFlowSettings()
14 | }
15 | }
--------------------------------------------------------------------------------
/composeApp/src/iosMain/kotlin/data.store/SettingsWrapper.ios.kt:
--------------------------------------------------------------------------------
1 | package data.store
2 |
3 | import com.russhwolf.settings.ExperimentalSettingsApi
4 | import com.russhwolf.settings.NSUserDefaultsSettings
5 | import com.russhwolf.settings.coroutines.FlowSettings
6 | import com.russhwolf.settings.coroutines.toFlowSettings
7 | import platform.Foundation.NSUserDefaults
8 |
9 | actual class SettingsWrapper {
10 | @OptIn(ExperimentalSettingsApi::class)
11 | actual fun createSettings(): FlowSettings {
12 | val delegate: NSUserDefaults = NSUserDefaults.standardUserDefaults
13 | return NSUserDefaultsSettings(delegate).toFlowSettings()
14 | }
15 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/ArticleModel.kt:
--------------------------------------------------------------------------------
1 | package data
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class ArticleSimpleModel(
8 | @SerialName("id")
9 | val id: String? = null,
10 | val authorId: String? = null,
11 | val authorName: String? = null,
12 | val createTime: String? = null,
13 | val authorAvatar: String? = null,
14 | val articleTitle: String? = null,
15 | val articleTagList: List? = null,
16 | val articleBrief: String? = null,
17 | val readNum: Int? = 0,
18 | val likeNum: Int? = 0,
19 | val commentNum: Int? = 0,
20 | )
--------------------------------------------------------------------------------
/composeApp/src/iosMain/kotlin/MainViewController.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.window.ComposeUIViewController
2 | import constant.enums.MainNavigationEnum
3 | import data.PlatformInitData
4 | import di.KoinInit
5 |
6 | fun MainViewController() = ComposeUIViewController(
7 | configure = {
8 | KoinInit().init {
9 | modules()
10 | }
11 | }
12 | ) { MainApp(
13 | platformData = PlatformInitData(
14 | extraNavigationList = listOf(
15 | MainNavigationEnum.ARTICLES,
16 | MainNavigationEnum.Contacts,
17 | MainNavigationEnum.MUSICS,
18 | MainNavigationEnum.SETTING,
19 | )
20 | )
21 | ) }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_circle_pause.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "",
4 | "project_id": "",
5 | "storage_bucket": ""
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:123456:android:123456",
11 | "android_client_info": {
12 | "package_name": "com.aster.yuno.tomoyo"
13 | }
14 | },
15 | "oauth_client": [],
16 | "api_key": [
17 | {
18 | "current_key": ""
19 | }
20 | ],
21 | "services": {
22 | "appinvite_service": {
23 | "other_platform_oauth_client": []
24 | }
25 | }
26 | }
27 | ],
28 | "configuration_version": ""
29 | }
30 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/ui/components/MediaPlayer.android.kt:
--------------------------------------------------------------------------------
1 | package ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.Modifier
5 |
6 | @Composable
7 | actual fun MediaPlayer(modifier: Modifier, url: String) {
8 | // AndroidView(
9 | // modifier = modifier,
10 | // factory = { context ->
11 | // VideoView(context).apply {
12 | // setVideoPath(url)
13 | // val mediaController = MediaController(context)
14 | // mediaController.setAnchorView(this)
15 | // setMediaController(mediaController)
16 | // start()
17 | // }
18 | // },
19 | // update = {})
20 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/id_badge_solid.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/envelope_alt.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_microphone.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_map_pin.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/skull_solid.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_repeat_all.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_folder.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_circle_play.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_play.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_circle_next.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_plus_square.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_map_marker.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_send.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_question_circle.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_circle_previous.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_next.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_tag.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_sliders_h.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_previous.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/stackoverflow.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/kotlin/biz/MainUtils.desktop.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import java.awt.KeyboardFocusManager
4 | import java.awt.Toolkit
5 | import java.awt.datatransfer.StringSelection
6 |
7 | actual fun copyToClipboard(text: String) {
8 | val clipboard = Toolkit.getDefaultToolkit().systemClipboard
9 | val stringSelection = StringSelection(text)
10 | clipboard.setContents(stringSelection, null)
11 | }
12 |
13 | actual fun logInfo(text: String) {
14 | }
15 |
16 | actual fun isAppInForeground(): Boolean {
17 | return KeyboardFocusManager.getCurrentKeyboardFocusManager().activeWindow != null;
18 | }
19 |
20 | actual fun afterLogin() {
21 | }
22 |
23 | actual fun beforeLogout() {
24 | }
25 |
26 | actual fun getPlatform(): String {
27 | return "desktop"
28 | }
29 |
30 | actual fun setUpdateGoogleFirebaseToken(operation: (String) -> Unit) {
31 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | API_KEY
6 |
7 | GCM_SENDER_ID
8 |
9 | PLIST_VERSION
10 | 1
11 | BUNDLE_ID
12 |
13 | PROJECT_ID
14 |
15 | STORAGE_BUCKET
16 |
17 | IS_ADS_ENABLED
18 |
19 | IS_ANALYTICS_ENABLED
20 |
21 | IS_APPINVITE_ENABLED
22 |
23 | IS_GCM_ENABLED
24 |
25 | IS_SIGNIN_ENABLED
26 |
27 | GOOGLE_APP_ID
28 |
29 |
30 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/drumstick_bite_solid.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_upload.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_audio.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_compass.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_film.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/twitter.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_heart.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_pause.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_circle_stop.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_user.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/user_graduate_solid.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_link.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/data/store/SettingsWrapper.android.kt:
--------------------------------------------------------------------------------
1 | package data.store
2 |
3 | import android.content.Context
4 | import androidx.datastore.preferences.preferencesDataStore
5 | import com.russhwolf.settings.ExperimentalSettingsApi
6 | import com.russhwolf.settings.ExperimentalSettingsImplementation
7 | import com.russhwolf.settings.coroutines.FlowSettings
8 | import com.russhwolf.settings.datastore.DataStoreSettings
9 | import org.koin.core.component.KoinComponent
10 | import org.koin.core.component.inject
11 |
12 | actual class SettingsWrapper : KoinComponent {
13 | private val context: Context by inject()
14 |
15 | companion object {
16 | private val Context.dataStore by preferencesDataStore("userSettings")
17 | }
18 |
19 |
20 | @OptIn(ExperimentalSettingsImplementation::class, ExperimentalSettingsApi::class)
21 | actual fun createSettings(): FlowSettings {
22 | return DataStoreSettings(context.dataStore)
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/composeApp/config/compose_compiler_config.conf:
--------------------------------------------------------------------------------
1 | com.github.panpf.sketch.Sketch
2 | com.github.panpf.sketch.PlatformContext
3 | com.github.panpf.sketch.drawable.DrawableEqualizer
4 | com.github.panpf.sketch.request.Image
5 | com.github.panpf.sketch.request.ImageOptions
6 | com.github.panpf.sketch.request.ImageRequest
7 | com.github.panpf.sketch.request.ImageResult
8 | com.github.panpf.sketch.state.ColorDrawableStateImage
9 | com.github.panpf.sketch.state.CurrentStateImage
10 | com.github.panpf.sketch.state.DrawableStateImage
11 | com.github.panpf.sketch.state.ErrorStateImage
12 | com.github.panpf.sketch.state.MemoryCacheStateImage
13 | com.github.panpf.sketch.state.IconAnimatableStateImage
14 | com.github.panpf.sketch.state.IconStateImage
15 | com.github.panpf.sketch.state.StateImage
16 | com.github.panpf.sketch.state.ThumbnailMemoryCacheStateImage
17 | com.github.panpf.sketch.util.ColorFetcher
18 | com.github.panpf.sketch.util.Equalizer
19 | com.github.panpf.sketch.util.IntColor
20 | com.github.panpf.sketch.util.Size
--------------------------------------------------------------------------------
/composeApp/src/iosMain/kotlin/biz/MainUtils.ios.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import platform.UIKit.UIApplication
4 | import platform.UIKit.UIApplicationState
5 | import platform.UIKit.UIPasteboard
6 |
7 | actual fun copyToClipboard(text: String) {
8 | UIPasteboard.generalPasteboard.string = text
9 | }
10 |
11 | actual fun logInfo(text: String) {
12 | }
13 |
14 | actual fun isAppInForeground(): Boolean {
15 | val application = UIApplication.sharedApplication
16 |
17 | return when (application.applicationState) {
18 | UIApplicationState.UIApplicationStateActive -> true
19 | UIApplicationState.UIApplicationStateInactive -> true
20 | UIApplicationState.UIApplicationStateBackground -> false
21 | else -> false
22 | }
23 | }
24 |
25 | actual fun afterLogin() {
26 | }
27 |
28 | actual fun beforeLogout() {
29 | }
30 |
31 | actual fun getPlatform(): String {
32 | return "mobile_ios"
33 | }
34 |
35 | actual fun setUpdateGoogleFirebaseToken(operation: (String) -> Unit) {
36 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_image.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_repeat_one.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_camera.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/envelope_question.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/envelope_heart.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/media_shuffle.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/github.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_trash.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 AsterCasc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_package.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_star.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/envelope_exclamation.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_map.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/kotlin/ui/components/Notification.desktop.kt:
--------------------------------------------------------------------------------
1 | package ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 | import koin
5 | import org.koin.core.qualifier.named
6 | import tray
7 | import java.awt.event.ActionListener
8 | import java.awt.image.BufferedImage
9 | import javax.swing.Timer
10 |
11 | val timer = Timer(500, object : ActionListener {
12 | var toggle = true
13 | val showIcon: BufferedImage = koin.get(named("superLowDpiIcon"))
14 | val hideIcon: BufferedImage = koin.get(named("hideIcon"))
15 |
16 |
17 | override fun actionPerformed(event: java.awt.event.ActionEvent?) {
18 | tray.trayIcons[0].image = if (toggle) showIcon else hideIcon
19 | toggle = !toggle
20 |
21 | }
22 | })
23 |
24 | actual fun sendAppNotification(title: String, content: String) {
25 | timer.start()
26 | }
27 |
28 | @Composable
29 | actual fun CheckAppNotificationPermission(
30 | requestPermission: @Composable (() -> Unit) -> Unit
31 | ) {
32 | }
33 |
34 | actual fun clearAppNotification() {
35 | timer.stop()
36 | val showIcon: BufferedImage = koin.get(named("superLowDpiIcon"))
37 |
38 | tray.trayIcons[0].image = showIcon
39 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/google.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_store.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/user_secret_solid.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_calendar.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/envelope_star.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/kotlin/di/CommonModule.desktop.kt:
--------------------------------------------------------------------------------
1 | package di
2 |
3 | import com.russhwolf.settings.ExperimentalSettingsApi
4 | import data.store.SettingsWrapper
5 | import org.koin.core.module.Module
6 | import org.koin.core.qualifier.named
7 | import org.koin.dsl.module
8 | import java.awt.image.BufferedImage
9 | import javax.imageio.ImageIO
10 |
11 | @OptIn(ExperimentalSettingsApi::class)
12 | actual fun platformModule(): Module = module {
13 | single { SettingsWrapper().createSettings() }
14 |
15 | single(qualifier = named("isMobile")) {
16 | false
17 | }
18 |
19 | single(qualifier = named("superLowDpiIcon")) {
20 | ImageIO.read(
21 | Thread.currentThread().contextClassLoader
22 | .getResource("logo_pro_round_32.png")
23 | )
24 | }
25 |
26 | single(qualifier = named("showIcon")) {
27 | ImageIO.read(
28 | Thread.currentThread().contextClassLoader
29 | .getResource("logo_pro_round.png")
30 | )
31 | }
32 |
33 | single(qualifier = named("hideIcon")) {
34 | ImageIO.read(
35 | Thread.currentThread().contextClassLoader
36 | .getResource("empty.png")
37 | )
38 |
39 |
40 | }
41 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_phone.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/di/CommonModule.kt:
--------------------------------------------------------------------------------
1 | package di
2 |
3 |
4 | import com.russhwolf.settings.ExperimentalSettingsApi
5 | import data.model.ArticleScreenModel
6 | import data.model.ChatScreenModel
7 | import data.model.ContactScreenModel
8 | import data.model.GlobalDataModel
9 | import data.model.MainScreenModel
10 | import data.model.MusicScreenModel
11 | import data.store.DataStorageManager
12 | import org.koin.core.module.Module
13 | import org.koin.dsl.module
14 |
15 | @OptIn(ExperimentalSettingsApi::class)
16 | fun commonModule() = module {
17 |
18 | //global
19 | single {
20 | GlobalDataModel()
21 | }
22 |
23 | //common
24 | single {
25 | ArticleScreenModel()
26 | }
27 |
28 | single {
29 | ChatScreenModel(dataStorageManager = get())
30 | }
31 |
32 | single {
33 | ContactScreenModel()
34 | }
35 |
36 | single {
37 | MusicScreenModel(dataStorageManager = get())
38 | }
39 |
40 | //main
41 | single {
42 | MainScreenModel()
43 | }
44 |
45 | //db
46 | single {
47 | DataStorageManager(settings = get())
48 | }
49 |
50 | }
51 |
52 | expect fun platformModule(): Module
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/store/DataStorageManager.kt:
--------------------------------------------------------------------------------
1 | package data.store
2 |
3 | import com.russhwolf.settings.ExperimentalSettingsApi
4 | import com.russhwolf.settings.ObservableSettings
5 | import com.russhwolf.settings.coroutines.FlowSettings
6 | import com.russhwolf.settings.coroutines.toBlockingObservableSettings
7 | import com.russhwolf.settings.set
8 |
9 | class DataStorageManager @OptIn(ExperimentalSettingsApi::class) constructor(private val settings: FlowSettings) {
10 |
11 | @OptIn(ExperimentalSettingsApi::class)
12 | private val observableSettings: ObservableSettings by lazy { settings.toBlockingObservableSettings() }
13 |
14 |
15 | fun setString(key: String, value: String) {
16 | observableSettings.set(key = key, value = value)
17 | }
18 |
19 | fun getNonFlowString(key: String) = observableSettings.getString(
20 | key = key,
21 | defaultValue = "",
22 | )
23 |
24 |
25 | fun clearPreferences() {
26 | observableSettings.clear()
27 | }
28 |
29 | companion object {
30 | const val USER_DATA = "user_data"
31 | const val FAV_AUDIO_ID_LIST = "fav_audio_id_list"
32 | const val RECENT_EMOJI_LIST = "recent_emoji_list"
33 | const val RECENT_KAOMOJI_LIST = "recent_kaomoji_list"
34 | const val RECENT_EMOJI_PRO_LIST = "recent_emoji_pro_list"
35 | const val USER_THEME = "user_theme"
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_users_three.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_globe.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/reddit.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/ui/pages/MainVideos.kt:
--------------------------------------------------------------------------------
1 | package ui.pages
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.Column
6 | import androidx.compose.foundation.layout.fillMaxSize
7 | import androidx.compose.foundation.layout.fillMaxWidth
8 | import androidx.compose.foundation.layout.height
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.unit.dp
13 | import cafe.adriel.voyager.core.screen.Screen
14 | import cafe.adriel.voyager.core.screen.ScreenKey
15 | import cafe.adriel.voyager.core.screen.uniqueScreenKey
16 | import constant.enums.ViewEnum
17 | import ui.components.MediaPlayer
18 |
19 |
20 | object MainVideosScreen : Screen {
21 |
22 | override val key: ScreenKey = "${ViewEnum.TAB_MAIN_VIDEOS.code}$uniqueScreenKey"
23 |
24 | @Composable
25 | override fun Content() {
26 | MainVideosScreen()
27 | }
28 |
29 | }
30 |
31 |
32 | @Composable
33 | fun MainVideosScreen() {
34 | Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
35 | Column(
36 | horizontalAlignment = Alignment.CenterHorizontally,
37 | verticalArrangement = Arrangement.SpaceAround
38 | ) {
39 | MediaPlayer(
40 | modifier = Modifier.fillMaxWidth().height(400.dp),
41 | url =
42 | ""
43 | )
44 |
45 |
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/MusicModel.kt:
--------------------------------------------------------------------------------
1 | package data
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.Stable
5 | import androidx.compose.runtime.getValue
6 | import androidx.compose.runtime.mutableStateOf
7 | import androidx.compose.runtime.remember
8 | import androidx.compose.runtime.setValue
9 | import constant.enums.MusicPlayModel
10 | import kotlinx.serialization.SerialName
11 | import kotlinx.serialization.Serializable
12 |
13 |
14 | @Serializable
15 | data class AudioSimpleModel(
16 | @SerialName("id")
17 | val id: String = "",
18 | val audioCollectionId: String? = null,
19 | val audioOrder: Int = 1,
20 | val audioName: String = "",
21 | val audioImg: String? = null,
22 | val audioBrief: String? = null,
23 | val audioAuthor: String = "",
24 | val audioUrl: String = "",
25 | )
26 |
27 | @Stable
28 | class MusicPlayerState {
29 | var isPlaying by mutableStateOf(false)
30 | internal set
31 | var isBuffering by mutableStateOf(false)
32 | var currentTime by mutableStateOf(0.0)
33 | var totalDuration by mutableStateOf(0.0)
34 |
35 | var currentPlayId by mutableStateOf("")
36 | var currentCollectionId by mutableStateOf("")
37 | var playModel by mutableStateOf(MusicPlayModel.ORDER.ordinal)
38 |
39 | fun toBack() {
40 | isPlaying = false
41 | isBuffering = false
42 | currentTime = 0.0
43 | totalDuration = 0.0
44 | }
45 | }
46 |
47 | @Composable
48 | fun rememberMusicPlayerState(): MusicPlayerState {
49 | return remember {
50 | MusicPlayerState()
51 | }
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "tomoyo"
2 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
3 |
4 |
5 | pluginManagement {
6 | repositories {
7 | // maven(url = "https://mirrors.cloud.tencent.com/gradle/")
8 |
9 | maven(url = "https://maven.aliyun.com/repository/public/")
10 | maven(url = "https://maven.aliyun.com/repository/jcenter/")
11 | maven(url = "https://maven.aliyun.com/repository/google/")
12 | maven(url = "https://maven.aliyun.com/repository/gradle-plugin/")
13 |
14 |
15 |
16 |
17 |
18 | google {
19 | mavenContent {
20 | includeGroupAndSubgroups("androidx")
21 | includeGroupAndSubgroups("com.android")
22 | includeGroupAndSubgroups("com.google")
23 | }
24 | }
25 | mavenCentral()
26 | gradlePluginPortal()
27 | }
28 | }
29 |
30 | dependencyResolutionManagement {
31 | repositories {
32 | maven("https://jogamp.org/deployment/maven")
33 |
34 | // maven(url = "https://mirrors.cloud.tencent.com/gradle/")
35 |
36 | // maven(url = "https://maven.aliyun.com/repository/public/")
37 | // maven(url = "https://maven.aliyun.com/repository/jcenter/")
38 | // maven(url = "https://maven.aliyun.com/repository/google/")
39 | // maven(url = "https://maven.aliyun.com/repository/gradle-plugin/")
40 |
41 |
42 | google {
43 | mavenContent {
44 | includeGroupAndSubgroups("androidx")
45 | includeGroupAndSubgroups("com.android")
46 | includeGroupAndSubgroups("com.google")
47 | }
48 | }
49 | mavenCentral()
50 | }
51 | }
52 |
53 | include(":composeApp")
--------------------------------------------------------------------------------
/iosApp/iosApp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | CADisableMinimumFrameDurationOnPhone
24 |
25 | UIApplicationSceneManifest
26 |
27 | UIApplicationSupportsMultipleScenes
28 |
29 |
30 | UILaunchScreen
31 |
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/biz/MainUtils.android.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.ActivityManager
5 | import android.content.ClipData
6 | import android.content.ClipboardManager
7 | import android.content.Context
8 | import android.util.Log
9 | import com.google.firebase.messaging.FirebaseMessaging
10 | import org.koin.java.KoinJavaComponent.inject
11 |
12 | actual fun copyToClipboard(text: String) {
13 | val context: Context by inject(Context::class.java)
14 | val clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
15 | val clipData = ClipData.newPlainText("Tomoyo Copy", text)
16 | clipboardManager.setPrimaryClip(clipData)
17 | }
18 |
19 | actual fun logInfo(text: String) {
20 | Log.i("Tomoyo", text)
21 | }
22 |
23 | @SuppressLint("ServiceCast")
24 | actual fun isAppInForeground(): Boolean {
25 | val context: Context by inject(Context::class.java)
26 | val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
27 | val appProcesses = activityManager.runningAppProcesses ?: return false
28 |
29 | val packageName = context.packageName
30 | for (appProcess in appProcesses) {
31 | if (appProcess.processName == packageName) {
32 | return appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
33 | }
34 | }
35 | return false
36 | }
37 |
38 | actual fun afterLogin() {
39 | reloadGoogleMessageToken()
40 | }
41 |
42 | actual fun beforeLogout() {
43 | FirebaseMessaging.getInstance().deleteToken()
44 | }
45 |
46 | actual fun getPlatform(): String {
47 | return "mobile_android"
48 | }
49 |
50 | actual fun setUpdateGoogleFirebaseToken(operation: (String) -> Unit) {
51 | updateGoogleFirebaseTokenFun = operation
52 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/model/ContactScreenModel.kt:
--------------------------------------------------------------------------------
1 | package data.model
2 |
3 | import api.BaseApi
4 | import cafe.adriel.voyager.core.model.ScreenModel
5 | import constant.enums.UserDetailTabScreenTabModel
6 | import data.PublicUserSimpleModel
7 | import data.UserDetailModel
8 | import kotlinx.coroutines.flow.MutableStateFlow
9 | import kotlinx.coroutines.flow.asStateFlow
10 |
11 | class ContactScreenModel : ScreenModel {
12 |
13 | private val _loadAllPublicUser = MutableStateFlow(false)
14 | val loadAllPublicUser = _loadAllPublicUser.asStateFlow()
15 |
16 | private val _publicUserDataList = MutableStateFlow(emptyList())
17 | val publicUserDataList = _publicUserDataList.asStateFlow()
18 | suspend fun loadPublicUser() {
19 | if (_publicUserDataList.value.isNotEmpty()) {
20 | return
21 | }
22 | _publicUserDataList.value = BaseApi().getPublicUser()
23 | _loadAllPublicUser.value = true
24 | }
25 |
26 | private val _userDetail = MutableStateFlow(UserDetailModel())
27 | val userDetail = _userDetail.asStateFlow()
28 | suspend fun updateUserDetail(userId: String) {
29 | if (_userDetail.value.id == userId) {
30 | return
31 | }
32 | val articleNum = BaseApi().getArticleCount(userId, 1)
33 | val thoughtNum = BaseApi().getArticleCount(userId, 2)
34 | val baseData = BaseApi().getUserDetail(userId)
35 | baseData.articleNum = articleNum
36 | baseData.thoughtNum = thoughtNum
37 | _userDetail.value = baseData
38 | }
39 |
40 | //tab
41 | private val _userDetailTab = MutableStateFlow(UserDetailTabScreenTabModel.FRIENDS)
42 | val userDetailTab = _userDetailTab.asStateFlow()
43 | fun updateUserDetailTab(tab: UserDetailTabScreenTabModel) {
44 | _userDetailTab.value = tab
45 | }
46 |
47 |
48 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/biz/StatusBar.android.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import android.app.Activity
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.runtime.SideEffect
6 | import androidx.compose.ui.graphics.Color
7 | import androidx.compose.ui.graphics.toArgb
8 | import androidx.compose.ui.platform.LocalView
9 | import androidx.core.view.WindowCompat
10 |
11 | actual class StatusBar actual constructor() {
12 | @Composable
13 | actual fun UpdateColor(
14 | statusBarColor: Color,
15 | navigationBarColor: Color,
16 | isLight: Boolean,
17 | ) {
18 | val view = LocalView.current
19 |
20 | if (!view.isInEditMode) {
21 | SideEffect {
22 | val window = (view.context as Activity).window
23 |
24 | val insetsController = WindowCompat.getInsetsController(window, view)
25 | window.statusBarColor = statusBarColor.toArgb()
26 | window.navigationBarColor = navigationBarColor.toArgb()
27 | insetsController.isAppearanceLightStatusBars = isLight
28 | insetsController.isAppearanceLightNavigationBars = isLight
29 |
30 | // same color to main
31 | // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
32 | // window.isNavigationBarContrastEnforced = false
33 | // }
34 | }
35 | }
36 |
37 |
38 |
39 |
40 |
41 | //use enableEdgeToEdge() instead
42 |
43 | // val view = LocalView.current
44 | // if (!view.isInEditMode) {
45 | // SideEffect {
46 | // val window = (view.context as Activity).window
47 | // window.statusBarColor = bgColor.toArgb()
48 | // WindowCompat.getInsetsController(window, view)
49 | // .isAppearanceLightStatusBars = textColorIsDark
50 | // }
51 | // }
52 | }
53 | }
--------------------------------------------------------------------------------
/composeApp/src/desktopMain/kotlin/ui/components/StartLoading.kt:
--------------------------------------------------------------------------------
1 | //package ui.components
2 | //
3 | //import javafx.application.Application
4 | //import javafx.scene.Scene
5 | //import javafx.scene.layout.StackPane
6 | //import javafx.scene.media.Media
7 | //import javafx.scene.media.MediaException
8 | //import javafx.scene.media.MediaPlayer
9 | //import javafx.scene.media.MediaView
10 | //import javafx.stage.Stage
11 | //
12 | //
13 | //class StartLoading : Application() {
14 | // override fun start(primaryStage: Stage) {
15 | // val videoUrl = "https://api.astercasc.com/ushio/video/play/VC1648909883875288/output.mp4"
16 | //
17 | //
18 | // // Create a Media object for the video
19 | // val media = Media(videoUrl)
20 | //
21 | //
22 | // // Create a MediaPlayer to control the playback of the media
23 | // val mediaPlayer = MediaPlayer(media)
24 | //
25 | //
26 | // // Handle media errors
27 | // mediaPlayer.onError = Runnable {
28 | // val error: MediaException = mediaPlayer.error
29 | // println("Media error occurred: " + error.message)
30 | // }
31 | //
32 | // // Handle media view errors
33 | // media.onError = Runnable {
34 | // val error: MediaException = media.error
35 | // println("Media error event: " + error.message)
36 | // }
37 | //
38 | //
39 | // // Create a MediaView to display the video
40 | // val mediaView = MediaView(mediaPlayer)
41 | //
42 | //
43 | // // Add the MediaView to a layout pane
44 | // val root = StackPane()
45 | // root.children.add(mediaView)
46 | //
47 | //
48 | // // Create and set up the scene
49 | // val scene = Scene(root, 800.0, 600.0)
50 | // primaryStage.setScene(scene)
51 | // primaryStage.setTitle("Web Video Player")
52 | // primaryStage.show()
53 | //
54 | // // Start playing the video
55 | // mediaPlayer.play()
56 | // }
57 | //
58 | //
59 | //}
60 | //
61 | //
62 | //
63 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/biz/FMessagingService.android.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import android.util.Log
4 | import com.google.firebase.messaging.FirebaseMessaging
5 | import com.google.firebase.messaging.FirebaseMessagingService
6 | import com.google.firebase.messaging.RemoteMessage
7 | import ui.components.sendAppNotification
8 |
9 | var globalGoogleFirebaseToken = ""
10 |
11 | var updateGoogleFirebaseTokenFun: (String) -> Unit = {}
12 |
13 | fun reloadGoogleMessageToken() {
14 | FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
15 | if (task.isSuccessful) {
16 | updaterToken(task.result)
17 | } else {
18 | Log.w("Tomoyo", "Failed to get google message token ", task.exception)
19 | }
20 | }
21 | }
22 |
23 | private fun updaterToken(token: String) {
24 | if (token != globalGoogleFirebaseToken) {
25 | globalGoogleFirebaseToken = token
26 | updateGoogleFirebaseTokenFun(token)
27 | Log.i("Tomoyo", "Current google message token: $globalGoogleFirebaseToken")
28 | }
29 | }
30 |
31 |
32 | class FMessagingService : FirebaseMessagingService() {
33 |
34 | override fun onNewToken(token: String) {
35 | super.onNewToken(token)
36 | updaterToken(token)
37 | }
38 |
39 | override fun onMessageReceived(remoteMessage: RemoteMessage) {
40 | super.onMessageReceived(remoteMessage)
41 |
42 | // Client notification
43 | remoteMessage.notification?.let {
44 | showNotification(it.title, it.body)
45 | }
46 |
47 | // Biz logic
48 | remoteMessage.data.let {
49 | if (it.isNotEmpty()) {
50 | processData(it)
51 | }
52 | }
53 | }
54 |
55 | private fun showNotification(title: String?, body: String?) {
56 | if (title.isNullOrBlank() && body.isNullOrBlank()) {
57 | sendAppNotification(title!!, body!!)
58 | }
59 | }
60 |
61 |
62 | private fun processData(data: Map) {
63 | }
64 |
65 | }
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/com/aster/yuno/tomoyo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.aster.yuno.tomoyo
2 |
3 | import MainApp
4 | import android.os.Bundle
5 | import androidx.activity.ComponentActivity
6 | import androidx.activity.compose.setContent
7 | import androidx.activity.enableEdgeToEdge
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.tooling.preview.Preview
10 | import biz.PlayerHolder
11 | import constant.enums.MainNavigationEnum
12 | import data.PlatformInitData
13 | import di.KoinInit
14 | import org.koin.android.ext.koin.androidContext
15 | import org.koin.android.ext.koin.androidLogger
16 | import org.koin.core.context.GlobalContext
17 | import ui.components.clearAppNotification
18 | import ui.components.createAppNotificationChannel
19 |
20 |
21 | class MainActivity : ComponentActivity() {
22 |
23 |
24 | override fun onCreate(savedInstanceState: Bundle?) {
25 |
26 | enableEdgeToEdge()
27 |
28 | super.onCreate(savedInstanceState)
29 |
30 | PlayerHolder.init(applicationContext)
31 |
32 | if (GlobalContext.getOrNull() == null) {
33 | KoinInit().init {
34 | androidLogger()
35 | androidContext(applicationContext)
36 | modules()
37 | }
38 | }
39 |
40 | createAppNotificationChannel(this)
41 |
42 | clearAppNotification()
43 |
44 | setContent {
45 | MainApp(
46 | platformData = PlatformInitData(
47 | extraNavigationList = listOf(
48 | MainNavigationEnum.ARTICLES,
49 | MainNavigationEnum.Contacts,
50 | MainNavigationEnum.MUSICS,
51 | MainNavigationEnum.SETTING,
52 | )
53 | )
54 | )
55 |
56 | }
57 | }
58 |
59 | override fun onResume() {
60 | super.onResume()
61 | clearAppNotification()
62 | }
63 | }
64 |
65 | @Preview
66 | @Composable
67 | fun AppAndroidPreview() {
68 | MainApp()
69 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/ChatModel.kt:
--------------------------------------------------------------------------------
1 | package data
2 |
3 | import kotlinx.coroutines.flow.MutableStateFlow
4 | import kotlinx.serialization.Serializable
5 |
6 |
7 | @Serializable
8 | data class UserChatStarEmojiSimple(
9 | var addressType: Int = 0,
10 | var id: String = "",
11 | var readAddress: String = "",
12 | )
13 |
14 |
15 | @Serializable
16 | data class UserChatStarEmojis(
17 | var fileEmojis: MutableList = mutableListOf(),
18 | var total: Int? = 0,
19 | )
20 |
21 | @Serializable
22 | data class UserChattingSimple(
23 | var chatId: String? = null,
24 | var chatType: Int? = null,
25 | var chatName: String? = null,
26 | var chatAvatar: String? = null,
27 | var chatUserId: String? = null,
28 | var chatUserGender: Int? = null,
29 | var chatUserRoleType: Int? = null,
30 | var lastMessageTime: String? = null,
31 | var lastMessageId: String? = null,
32 | var userChattingData: MutableList = mutableListOf(),
33 | var latestRead: Boolean? = null,
34 | var lastMessageText: String? = null,
35 |
36 | var userChattingDataFlow: MutableStateFlow> = MutableStateFlow(emptyList()),
37 | var clientLoadAllHistoryMessage: MutableStateFlow = MutableStateFlow(false),
38 | var latestReadWeb: MutableStateFlow = MutableStateFlow(true),
39 | )
40 |
41 |
42 | @Serializable
43 | data class UserChatMsgDto(
44 | var messageId: String? = null,
45 | var sendUserId: String? = null,
46 | var sendUserNickname: String? = null,
47 | var sendUserAvatar: String? = null,
48 | var sendUserGender: Int? = null,
49 | var sendUserRoleType: Int? = null,
50 | var sendDate: String? = null,
51 | var message: String? = null,
52 | //web
53 | var webChatLabel: String? = null,
54 | )
55 |
56 | @Serializable
57 | data class UserChatParam(
58 | val toUserId: String
59 | )
60 |
61 |
62 | @Serializable
63 | data class UserUploadRetDto(
64 | val id: String?,
65 | val readAddress: String?
66 | )
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/model/GlobalDataModel.kt:
--------------------------------------------------------------------------------
1 | package data.model
2 |
3 | import api.BaseApi
4 | import biz.logInfo
5 | import data.UserChatStarEmojiSimple
6 | import data.UserDataModel
7 | import data.UserExData
8 | import data.UserState
9 | import kotlinx.coroutines.flow.MutableStateFlow
10 | import kotlinx.coroutines.flow.asStateFlow
11 | import kotlinx.coroutines.flow.update
12 |
13 | class GlobalDataModel {
14 |
15 | //user data
16 | private val _userState = MutableStateFlow(UserState())
17 | val userState = _userState.asStateFlow()
18 |
19 | fun clearLocalUserState() {
20 | logInfo("[op:clearLocalUserState] User data clear")
21 | _userState.value.userData = UserDataModel()
22 | _userState.value.token = ""
23 | clearLocalUserExData()
24 | }
25 |
26 | private val _userExData = UserExData()
27 | fun getUserExData(): UserExData {
28 | return _userExData
29 | }
30 |
31 | fun resetUserEmoji(data: List) {
32 | _userExData.emojiProListFlow.update { currentList ->
33 | currentList.toMutableList().apply {
34 | this.addAll(data)
35 | }
36 | }
37 | }
38 |
39 | fun clearLocalUserExData() {
40 | _userExData.emojiProListFlow.update { currentList ->
41 | currentList.toMutableList().apply {
42 | this.clear()
43 | }
44 | }
45 | }
46 |
47 | //network
48 | private val _netStatus = MutableStateFlow(true)
49 | val netStatus = _netStatus.asStateFlow()
50 |
51 | suspend fun checkNetwork() {
52 | _netStatus.value = BaseApi().checkNetwork()
53 | }
54 |
55 | fun resetNetStatus(status: Boolean) {
56 | _netStatus.value = status
57 | }
58 |
59 | //socket
60 | private val _socketConnected = MutableStateFlow(true)
61 | val socketConnected = _socketConnected.asStateFlow()
62 | fun resetSocketConnected(status: Boolean) {
63 | logInfo("[op:resetSocketConnected] reset")
64 | _socketConnected.value = status
65 | }
66 |
67 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/model/ArticleScreenModel.kt:
--------------------------------------------------------------------------------
1 | package data.model
2 |
3 | import api.BaseApi
4 | import cafe.adriel.voyager.core.model.ScreenModel
5 | import data.ArticleSimpleModel
6 | import kotlinx.coroutines.flow.MutableStateFlow
7 | import kotlinx.coroutines.flow.asStateFlow
8 |
9 | class ArticleScreenModel : ScreenModel {
10 |
11 | private val _articleDataKey = MutableStateFlow("")
12 | val articleDataKey = _articleDataKey.asStateFlow()
13 | private val _articleIsLoadAll = MutableStateFlow(false)
14 | val articleIsLoadAll = _articleIsLoadAll.asStateFlow()
15 |
16 | private val _articleDataList = MutableStateFlow(emptyList())
17 | val articleDataList = _articleDataList.asStateFlow()
18 | suspend fun updateArticleList() {
19 | val newData = BaseApi().getArticleList(
20 | offset = _articleDataList.value.size,
21 | keyword = _articleDataKey.value
22 | )
23 | _articleIsLoadAll.value = newData.isEmpty()
24 | _articleDataList.value += newData
25 | }
26 |
27 | fun clearResetKeyword(keyword: String = "") {
28 | _articleDataKey.value = keyword
29 | _articleDataList.value = emptyList()
30 | }
31 |
32 | private val _readingArticleId = MutableStateFlow("")
33 | private val _readingArticleMeta = MutableStateFlow(ArticleSimpleModel())
34 | val readingArticleMeta = _readingArticleMeta.asStateFlow()
35 | private val _readingArticleData = MutableStateFlow("")
36 | val readingArticleData = _readingArticleData.asStateFlow()
37 | fun updateReadingMeta(data: ArticleSimpleModel) {
38 | _readingArticleMeta.value = data
39 | }
40 | suspend fun updateReadingArticleData(articleId: String, token: String) {
41 | if (_readingArticleId.value == articleId) {
42 | return
43 | }
44 | val content = BaseApi().getArticleDetail(articleId, token)
45 | if (content.isNotBlank()) {
46 | _readingArticleData.value = content
47 | _readingArticleId.value = articleId
48 | } else {
49 | _readingArticleId.value = articleId
50 | _readingArticleData.value = "Not Login"
51 | }
52 |
53 | }
54 |
55 |
56 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/amazon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/biz/ChatSocketService.android.kt:
--------------------------------------------------------------------------------
1 | package biz
2 |
3 | import android.app.Notification
4 | import android.app.NotificationChannel
5 | import android.app.NotificationManager
6 | import android.app.PendingIntent
7 | import android.app.Service
8 | import android.content.Context
9 | import android.content.Intent
10 | import android.os.IBinder
11 | import androidx.core.app.NotificationCompat
12 | import com.aster.yuno.tomoyo.MainActivity
13 | import com.aster.yuno.tomoyo.R
14 |
15 | class ChatSocketService : Service() {
16 |
17 | override fun onCreate() {
18 | super.onCreate()
19 |
20 | createNotificationChannel()
21 | val notification = buildNotification()
22 | startForeground(NOTIFICATION_ID, notification)
23 | }
24 |
25 | override fun onBind(intent: Intent?): IBinder? {
26 | return null
27 | }
28 |
29 | private fun createNotificationChannel() {
30 | val name = "Chat Service"
31 | val descriptionText = "Service for Chat socket"
32 | val importance = NotificationManager.IMPORTANCE_LOW
33 | val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
34 | description = descriptionText
35 | }
36 | val notificationManager: NotificationManager =
37 | getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
38 | notificationManager.createNotificationChannel(channel)
39 | }
40 |
41 | private fun buildNotification(): Notification {
42 | val intent = Intent(this, MainActivity::class.java).apply {
43 | flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
44 | }
45 | val pendingIntent: PendingIntent =
46 | PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
47 |
48 | return NotificationCompat.Builder(this, CHANNEL_ID)
49 | .setContentTitle("Tomoyo")
50 | .setContentText("Getting message ...")
51 | .setSmallIcon(R.drawable.logo_pro_background)
52 | .setContentIntent(pendingIntent)
53 | .setOngoing(true)
54 | .build()
55 | }
56 |
57 | companion object {
58 | private const val CHANNEL_ID = "ChatSocketChannel"
59 | private const val NOTIFICATION_ID = 2
60 | }
61 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/input_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package theme
2 |
3 | import androidx.compose.material3.MaterialTheme
4 | import androidx.compose.material3.Typography
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.text.font.FontFamily
7 | import tomoyo.composeapp.generated.resources.Res
8 | import tomoyo.composeapp.generated.resources.RobotoSlab_VariableFont_wght
9 |
10 | @Composable
11 | fun MainTypography(): Typography {
12 |
13 | val defaultFontFamily = FontFamily(
14 | org.jetbrains.compose.resources.Font(
15 | Res.font.RobotoSlab_VariableFont_wght
16 | )
17 | )
18 |
19 | return Typography(
20 | labelSmall = MaterialTheme.typography.labelSmall.copy(
21 | fontFamily = defaultFontFamily,
22 | ),
23 | labelMedium = MaterialTheme.typography.labelMedium.copy(
24 | fontFamily = defaultFontFamily,
25 | ),
26 | labelLarge = MaterialTheme.typography.labelLarge.copy(
27 | fontFamily = defaultFontFamily,
28 | //fontWeight = FontWeight.Bold,
29 | ),
30 | bodySmall = MaterialTheme.typography.bodySmall.copy(
31 | fontFamily = defaultFontFamily,
32 | ),
33 | bodyMedium = MaterialTheme.typography.bodyMedium.copy(
34 | fontFamily = defaultFontFamily,
35 | ),
36 | bodyLarge = MaterialTheme.typography.bodyLarge.copy(
37 | fontFamily = defaultFontFamily,
38 | //fontWeight = FontWeight.Bold,
39 | ),
40 | titleSmall = MaterialTheme.typography.titleSmall.copy(
41 | fontFamily = defaultFontFamily,
42 | ),
43 | titleMedium = MaterialTheme.typography.titleMedium.copy(
44 | fontFamily = defaultFontFamily,
45 | ),
46 | titleLarge = MaterialTheme.typography.titleLarge.copy(
47 | fontFamily = defaultFontFamily,
48 | ),
49 | headlineSmall = MaterialTheme.typography.headlineSmall.copy(
50 | fontFamily = defaultFontFamily,
51 | ),
52 | headlineMedium = MaterialTheme.typography.headlineMedium.copy(
53 | fontFamily = defaultFontFamily,
54 | ),
55 | headlineLarge = MaterialTheme.typography.headlineLarge.copy(
56 | fontFamily = defaultFontFamily,
57 | ),
58 |
59 | )
60 | }
61 |
--------------------------------------------------------------------------------
/composeApp/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
39 |
40 |
45 |
46 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/UserModel.kt:
--------------------------------------------------------------------------------
1 | package data
2 |
3 | import androidx.compose.runtime.Stable
4 | import androidx.compose.runtime.getValue
5 | import androidx.compose.runtime.mutableStateOf
6 | import androidx.compose.runtime.setValue
7 | import kotlinx.coroutines.flow.MutableStateFlow
8 | import kotlinx.datetime.LocalDate
9 | import kotlinx.serialization.Serializable
10 |
11 | @Serializable
12 | data class UserSocialLinkDto(
13 | var qq: String? = null,
14 | var wechat: String? = null,
15 | var github: String? = null,
16 | )
17 |
18 | @Serializable
19 | data class UserCommunityModel(
20 | var followNum: Int = 0,
21 | var fansNum: Int = 0,
22 | var friendNum: Int = 0,
23 | )
24 |
25 | @Serializable
26 | data class UserDetailModel(
27 | var id: String = "",
28 | var nickName: String = "",
29 | var gender: Int = 1,
30 | var roleType: Int = 1,
31 | var avatar: String = "",
32 | var motto: String? = null,
33 | var mail: String = "",
34 | var birth: LocalDate = LocalDate.fromEpochDays(0),
35 | var friendList: List = emptyList(),
36 | var community: UserCommunityModel = UserCommunityModel(),
37 | var socialLink: UserSocialLinkDto = UserSocialLinkDto(),
38 | //insert data
39 | var articleNum: Int? = null,
40 | var thoughtNum: Int? = null,
41 | )
42 |
43 | @Serializable
44 | data class UserDataModel(
45 | var id: String? = null,
46 | var mail: String? = null,
47 | var account: String? = null,
48 | var avatar: String? = null,
49 | var nickName: String? = null,
50 | var token: String? = null,
51 | )
52 |
53 | @Serializable
54 | data class PublicUserSimpleModel(
55 | var id: String = "",
56 | var nickName: String = "",
57 | var gender: Int = 1,
58 | var roleType: Int = 1,
59 | var avatar: String = "",
60 | var motto: String? = null,
61 | )
62 |
63 | @Stable
64 | class UserState {
65 | var token by mutableStateOf("")
66 | var userData by mutableStateOf(UserDataModel())
67 | }
68 |
69 | @Serializable
70 | class UserExData {
71 | val emojiProListFlow: MutableStateFlow> =
72 | MutableStateFlow(emptyList())
73 | }
74 |
75 | @Serializable
76 | data class LoginParam(
77 | val accountMail: String,
78 | val passwd: String,
79 | )
80 |
81 | @Serializable
82 | data class ChatRowModel(
83 | val fromChatId: String = "",
84 | val sendUserId: String = "",
85 | val sendUserRoleType: Int = 0,
86 | val sendUserGender: Int = 0,
87 | val sendMessageId: String = "",
88 | val sendUserAvatar: String = "",
89 | val sendMessage: String = "",
90 | val sendUserNickname: String = "",
91 | val sendDate: String = "",
92 | )
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/constant/BaseConstants.kt:
--------------------------------------------------------------------------------
1 | package constant
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 |
6 | object BaseResText {
7 | var deleteImageProConfirm: String = ""
8 | var errorTooLargeUpload5000: String = ""
9 | var errorTooLargeUpload20: String = ""
10 | var userNoLogin: String = ""
11 | var underDevelopment: String = ""
12 | var confirmBtn: String = ""
13 | var cancelBtn: String = ""
14 | var copyTip: String = ""
15 | var bgColorList: List = listOf(Color.White, Color.White)
16 | var weekDayList: List = listOf("", "", "", "", "", "", "", "")
17 | }
18 |
19 | const val RECENT_EMOJI_MAX_SIZE = 8;
20 | const val BASE_SERVER_ADDRESS = "https://api.astercasc.com"
21 | const val BASE_SERVER_ADDRESS_STATIC = "https://api.astercasc.com/public/resources/"
22 | const val EMOJI_REPLACE_KEY = "EMOJI_PLACEHOLDER"
23 | const val NETWORK_CHECK_HOST = "https://www.baidu.com"
24 | const val MAX_TIME_SPE_SEC = 600
25 | //val ANN_TEXT_MAP = mapOf(
26 | // EMOJI_REPLACE_KEY to InlineTextContent(
27 | // Placeholder(
28 | // width = 25.sp,
29 | // height = 25.sp,
30 | // placeholderVerticalAlign = PlaceholderVerticalAlign.TextCenter
31 | // )
32 | // ) { emoji ->
33 | // Image(
34 | // painter = painterResource(
35 | // biliEmojiMap[emoji] ?: Res.drawable.bili_00
36 | // ),
37 | // modifier = Modifier.fillMaxSize(),
38 | // contentDescription = null,
39 | // )
40 | // }
41 | //)
42 |
43 | //私人编码:
44 | //Basic Multilingual Plane : U+E000 至 U+F8FF (57344 - 59647)
45 | //Supplementary Private Use Area-A : U+F0000 至 U+FFFFD
46 | //Supplementary Private Use Area-B: U+100000 (\uD800\uDC00) 至 U+10FFFD (\uDBFF\uDFFD)
47 |
48 |
49 | val emojiList = listOf(
50 | "🤭", "😄", "😁", "😆", "😅", "😂", "🤣", "😊", "😇",
51 | "🙂", "🙃", "😉", "😌", "😍", "🥰", "😘", "😗", "😙", "😚",
52 | "😋", "😛", "😜", "🤪", "😝", "🤑", "🤗", "🤭", "🤫", "🤔",
53 | "🤐", "🤨", "😐", "😑", "😶", "😏", "😒", "🙄", "😬", "😔",
54 | "😪", "😴", "😷", "🤒", "🤕", "🤢", "🤮", "🤧", "😵", "🤯",
55 | "😳", "🥵", "🥶", "😱", "😨", "😰", "😥", "😢", "😭", "😤",
56 | "😠", "😡", "🤬", "🤯", "😳", "🥱", "😤",
57 | )
58 |
59 |
60 | val kaomojiList = listOf(
61 | "(^▽^)", "(≧▽≦)", "(´▽`)", "(๑˃ᴗ˂)ﻭ", "( ̄▽ ̄)ノ",
62 | "(*^▽^*)", "(^‿^)", "(^ω^)", "(o^∀^o)", "(≧ω≦)",
63 | "(o´▽`o)", "(@^-^)", "(≧∇≦)ノ", "(*´▽`*)", "(^-^)v",
64 | "(ヽ*^ω^*)ノ", "(๑´ڡ`๑)", "( •̀ ω •́ )✧", "(*^3^)/~☆",
65 | "(≧∇≦)/", "(。♥‿♥。)", "(。•ㅅ•。)♡", "(。・ω・。)ノ♡", "(ฅ•ω•ฅ)♡",
66 | "(๑•́ ₃ •̀๑)", "(´・ω・`)", "(。•́︿•̀。)", "(。♥‿♥。)",
67 | "(*≧ω≦)", "(∩_∩)", "( ̄3 ̄)", "(๑°3°๑)", "(,,• •,,)♡",
68 | "(。・//ε//・。)", "(づ ̄ ³ ̄)づ", "(´∀`)♡", "( ˘ ³˘)♥",
69 | "(๑´•.̫ • `๑)", "(づ。◕‿‿◕。)づ", "(´,,•ω•,,`)♡", "(〃ω〃)",
70 | "(⁄ ⁄•⁄ω⁄•⁄ ⁄)", "(。・//ω//・。)", "(*ノωノ)", "(´//ω//`)",
71 | "(*ฅ́˘ฅ̀*)", "(*/ω\*)", "(๑•́‧̫•̀๑)", "(´,,•ω•,,`)",
72 | "(//▽//)", "(。•́︿•̀。)", "(T_T)", "(ಥ_ಥ)",
73 | "(இ﹏இ`。)", "(〒︿〒)", "(╯︵╰,)", "(ಥ﹏ಥ)", "(。•́︿•̀。)",
74 | "(ノ_・。)", "(´;д;`)", "(;′⌒`)", "(つω`。)", "(ᗒᗩᗕ)",
75 | "(。•́︿•̀。)", "(╥﹏╥)", "(ಥ_ಥ)", "。:゚(。ノω\。)゚・。", "(つд⊂)",
76 | "(╥ω╥)", "(#`皿´)", "( ̄へ ̄)", "(≧ヘ≦ )", "(눈_눈)", "(¬_¬)",
77 | "(╬ಠ益ಠ)", "(。•ˇ‸ˇ•。)", "(`⌒´メ)", "(⇀‸↼‶)", "(¬‿¬)",
78 | "(°ロ°) !?", "(・o・)", "(๑•̀ㅁ•́๑)", "(⊙_◎)", "Σ(°ロ°)",
79 | "(°ー°〃)", "Σ( ̄□ ̄||)", "(⊙_⊙')", "(☉。☉)!", "(o_O)",
80 | "( ̄ー ̄)", "(¬_¬)", "(≖_≖ )", "( ´_ゝ`)", "(ಠ_ಠ)", "(; ̄Д ̄)",
81 | )
82 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/ui/components/CardComponents.kt:
--------------------------------------------------------------------------------
1 | package ui.components
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.gestures.detectHorizontalDragGestures
6 | import androidx.compose.foundation.layout.Arrangement
7 | import androidx.compose.foundation.layout.Box
8 | import androidx.compose.foundation.layout.Row
9 | import androidx.compose.foundation.layout.fillMaxHeight
10 | import androidx.compose.foundation.layout.fillMaxSize
11 | import androidx.compose.foundation.layout.fillMaxWidth
12 | import androidx.compose.foundation.layout.offset
13 | import androidx.compose.foundation.layout.width
14 | import androidx.compose.material3.Text
15 | import androidx.compose.runtime.Composable
16 | import androidx.compose.runtime.getValue
17 | import androidx.compose.runtime.mutableStateOf
18 | import androidx.compose.runtime.remember
19 | import androidx.compose.runtime.setValue
20 | import androidx.compose.ui.Alignment
21 | import androidx.compose.ui.Modifier
22 | import androidx.compose.ui.graphics.Color
23 | import androidx.compose.ui.input.pointer.pointerInput
24 | import androidx.compose.ui.platform.LocalDensity
25 | import androidx.compose.ui.unit.Dp
26 | import androidx.compose.ui.unit.IntOffset
27 | import kotlin.math.max
28 | import kotlin.math.min
29 |
30 | data class SwipeToRevealCardOption(
31 | val optionText: String,
32 | val optionOperation: () -> Unit,
33 | val width: Dp,
34 | val optColor: Color,
35 | val optBgColor: Color,
36 | )
37 |
38 |
39 | @Composable
40 | fun SwipeToRevealCard(
41 | modifier: Modifier = Modifier,
42 | optionList: List = emptyList(),
43 | content: @Composable () -> Unit
44 | ) {
45 |
46 | var offsetX by remember { mutableStateOf(0f) }
47 | val maxOffsetDp = optionList.map { it.width }.reduce { acc, dp -> acc + dp }
48 | val maxOffset = with(LocalDensity.current) { maxOffsetDp.toPx() }
49 |
50 | Box(
51 | modifier = modifier
52 | ) {
53 | Row(
54 | modifier = Modifier.fillMaxWidth()
55 | .offset { IntOffset(offsetX.toInt() + maxOffset.toInt(), 0) },
56 | horizontalArrangement = Arrangement.End,
57 | verticalAlignment = Alignment.CenterVertically,
58 | ) {
59 |
60 | for (opt in optionList) {
61 | Box(
62 | modifier = Modifier.fillMaxHeight()
63 | .width(opt.width).background(opt.optBgColor)
64 | .clickable {
65 | offsetX = 0f
66 | opt.optionOperation()
67 | }, contentAlignment = Alignment.Center
68 | ) {
69 | Text(
70 | modifier = Modifier, text = opt.optionText, color = opt.optColor
71 | )
72 | }
73 | }
74 |
75 | }
76 |
77 | Box(modifier = Modifier.offset { IntOffset(offsetX.toInt(), 0) }.fillMaxSize()
78 | .pointerInput(Unit) {
79 | detectHorizontalDragGestures(onHorizontalDrag = { _, dragAmount ->
80 | val newOffset = offsetX + dragAmount
81 | offsetX = max(-maxOffset, min(0f, newOffset))
82 | }, onDragEnd = {
83 | offsetX = if (offsetX < -maxOffset / 2) {
84 | (-maxOffset)
85 | } else {
86 | 0f
87 | }
88 | })
89 | }) {
90 | content()
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/constant/ChineseDateData.kt:
--------------------------------------------------------------------------------
1 | package constant
2 |
3 | val LUNAR_CODE = longArrayOf(
4 | 0x04bd8,
5 | 0x04ae0,
6 | 0x0a570,
7 | 0x054d5,
8 | 0x0d260,
9 | 0x0d950,
10 | 0x16554,
11 | 0x056a0,
12 | 0x09ad0,
13 | 0x055d2, //1900-1909
14 | 0x04ae0,
15 | 0x0a5b6,
16 | 0x0a4d0,
17 | 0x0d250,
18 | 0x1d255,
19 | 0x0b540,
20 | 0x0d6a0,
21 | 0x0ada2,
22 | 0x095b0,
23 | 0x14977, //1910-1919
24 | 0x04970,
25 | 0x0a4b0,
26 | 0x0b4b5,
27 | 0x06a50,
28 | 0x06d40,
29 | 0x1ab54,
30 | 0x02b60,
31 | 0x09570,
32 | 0x052f2,
33 | 0x04970, //1920-1929
34 | 0x06566,
35 | 0x0d4a0,
36 | 0x0ea50,
37 | 0x16a95,
38 | 0x05ad0,
39 | 0x02b60,
40 | 0x186e3,
41 | 0x092e0,
42 | 0x1c8d7,
43 | 0x0c950, //1930-1939
44 | 0x0d4a0,
45 | 0x1d8a6,
46 | 0x0b550,
47 | 0x056a0,
48 | 0x1a5b4,
49 | 0x025d0,
50 | 0x092d0,
51 | 0x0d2b2,
52 | 0x0a950,
53 | 0x0b557, //1940-1949
54 | 0x06ca0,
55 | 0x0b550,
56 | 0x15355,
57 | 0x04da0,
58 | 0x0a5b0,
59 | 0x14573,
60 | 0x052b0,
61 | 0x0a9a8,
62 | 0x0e950,
63 | 0x06aa0, //1950-1959
64 | 0x0aea6,
65 | 0x0ab50,
66 | 0x04b60,
67 | 0x0aae4,
68 | 0x0a570,
69 | 0x05260,
70 | 0x0f263,
71 | 0x0d950,
72 | 0x05b57,
73 | 0x056a0, //1960-1969
74 | 0x096d0,
75 | 0x04dd5,
76 | 0x04ad0,
77 | 0x0a4d0,
78 | 0x0d4d4,
79 | 0x0d250,
80 | 0x0d558,
81 | 0x0b540,
82 | 0x0b6a0,
83 | 0x195a6, //1970-1979
84 | 0x095b0,
85 | 0x049b0,
86 | 0x0a974,
87 | 0x0a4b0,
88 | 0x0b27a,
89 | 0x06a50,
90 | 0x06d40,
91 | 0x0af46,
92 | 0x0ab60,
93 | 0x09570, //1980-1989
94 | 0x04af5,
95 | 0x04970,
96 | 0x064b0,
97 | 0x074a3,
98 | 0x0ea50,
99 | 0x06b58,
100 | 0x05ac0,
101 | 0x0ab60,
102 | 0x096d5,
103 | 0x092e0, //1990-1999
104 | 0x0c960,
105 | 0x0d954,
106 | 0x0d4a0,
107 | 0x0da50,
108 | 0x07552,
109 | 0x056a0,
110 | 0x0abb7,
111 | 0x025d0,
112 | 0x092d0,
113 | 0x0cab5, //2000-2009
114 | 0x0a950,
115 | 0x0b4a0,
116 | 0x0baa4,
117 | 0x0ad50,
118 | 0x055d9,
119 | 0x04ba0,
120 | 0x0a5b0,
121 | 0x15176,
122 | 0x052b0,
123 | 0x0a930, //2010-2019
124 | 0x07954,
125 | 0x06aa0,
126 | 0x0ad50,
127 | 0x05b52,
128 | 0x04b60,
129 | 0x0a6e6,
130 | 0x0a4e0,
131 | 0x0d260,
132 | 0x0ea65,
133 | 0x0d530, //2020-2029
134 | 0x05aa0,
135 | 0x076a3,
136 | 0x096d0,
137 | 0x04afb,
138 | 0x04ad0,
139 | 0x0a4d0,
140 | 0x1d0b6,
141 | 0x0d250,
142 | 0x0d520,
143 | 0x0dd45, //2030-2039
144 | 0x0b5a0,
145 | 0x056d0,
146 | 0x055b2,
147 | 0x049b0,
148 | 0x0a577,
149 | 0x0a4b0,
150 | 0x0aa50,
151 | 0x1b255,
152 | 0x06d20,
153 | 0x0ada0, //2040-2049
154 | 0x14b63,
155 | 0x09370,
156 | 0x049f8,
157 | 0x04970,
158 | 0x064b0,
159 | 0x168a6,
160 | 0x0ea50,
161 | 0x06b20,
162 | 0x1a6c4,
163 | 0x0aae0, //2050-2059
164 | 0x092e0,
165 | 0x0d2e3,
166 | 0x0c960,
167 | 0x0d557,
168 | 0x0d4a0,
169 | 0x0da50,
170 | 0x05d55,
171 | 0x056a0,
172 | 0x0a6d0,
173 | 0x055d4, //2060-2069
174 | 0x052d0,
175 | 0x0a9b8,
176 | 0x0a950,
177 | 0x0b4a0,
178 | 0x0b6a6,
179 | 0x0ad50,
180 | 0x055a0,
181 | 0x0aba4,
182 | 0x0a5b0,
183 | 0x052b0, //2070-2079
184 | 0x0b273,
185 | 0x06930,
186 | 0x07337,
187 | 0x06aa0,
188 | 0x0ad50,
189 | 0x14b55,
190 | 0x04b60,
191 | 0x0a570,
192 | 0x054e4,
193 | 0x0d160, //2080-2089
194 | 0x0e968,
195 | 0x0d520,
196 | 0x0daa0,
197 | 0x16aa6,
198 | 0x056d0,
199 | 0x04ae0,
200 | 0x0a9d4,
201 | 0x0a2d0,
202 | 0x0d150,
203 | 0x0f252, //2090-2099
204 | )
--------------------------------------------------------------------------------
/composeApp/src/androidMain/kotlin/ui/components/Notification.android.kt:
--------------------------------------------------------------------------------
1 | package ui.components
2 |
3 |
4 | import android.Manifest
5 | import android.annotation.SuppressLint
6 | import android.app.NotificationChannel
7 | import android.app.NotificationManager
8 | import android.app.PendingIntent
9 | import android.content.Context
10 | import android.content.Intent
11 | import android.os.Build
12 | import android.provider.Settings
13 | import androidx.annotation.RequiresApi
14 | import androidx.compose.runtime.Composable
15 | import androidx.compose.ui.platform.LocalContext
16 | import androidx.core.app.NotificationCompat
17 | import com.aster.yuno.tomoyo.MainActivity
18 | import com.google.accompanist.permissions.ExperimentalPermissionsApi
19 | import com.google.accompanist.permissions.isGranted
20 | import com.google.accompanist.permissions.rememberPermissionState
21 | import org.koin.java.KoinJavaComponent.inject
22 |
23 | @SuppressLint("PermissionLaunchedDuringComposition")
24 | @RequiresApi(Build.VERSION_CODES.TIRAMISU)
25 | @ExperimentalPermissionsApi
26 | @Composable
27 | actual fun CheckAppNotificationPermission(
28 | requestPermission: @Composable (() -> Unit) -> Unit
29 | ) {
30 |
31 | val context = LocalContext.current
32 |
33 | val notificationPermission = rememberPermissionState(
34 | permission = Manifest.permission.POST_NOTIFICATIONS
35 | )
36 |
37 | if (!notificationPermission.status.isGranted) {
38 |
39 | requestPermission {
40 | //function 1
41 | //notificationPermission.launchPermissionRequest()
42 |
43 | //function 2
44 | val intent = Intent().apply {
45 | action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
46 | putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
47 | }
48 |
49 | //function 3
50 | // val intent = Intent().apply {
51 | // action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
52 | // data = Uri.fromParts("package", context.packageName, null)
53 | // }
54 | context.startActivity(intent)
55 | }
56 |
57 |
58 | }
59 |
60 | //Toast.makeText(LocalContext.current, "Permission Check", Toast.LENGTH_SHORT).show()
61 | }
62 |
63 | fun createAppNotificationChannel(context: Context) {
64 | val channel = NotificationChannel(
65 | "TomoyoCommonChannel",
66 | "Tomoyo Common Notification",
67 | NotificationManager.IMPORTANCE_HIGH
68 | ).apply {
69 | this.description = description
70 | enableLights(true)
71 | enableVibration(true)
72 | setShowBadge(true)
73 | setBypassDnd(true)
74 | }
75 |
76 | val notificationManager = context.getSystemService(NotificationManager::class.java)
77 | notificationManager.createNotificationChannel(channel)
78 | }
79 |
80 |
81 | actual fun sendAppNotification(title: String, content: String) {
82 | val context: Context by inject(Context::class.java)
83 |
84 | val intent = Intent(context, MainActivity::class.java).apply {
85 | flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
86 | }
87 | val pendingIntent = PendingIntent.getActivity(
88 | context,
89 | 0,
90 | intent,
91 | PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
92 | )
93 |
94 |
95 | val builder = NotificationCompat.Builder(context, "TomoyoCommonChannel")
96 | .setContentTitle(title)
97 | .setContentText(content)
98 | .setSmallIcon(android.R.drawable.ic_dialog_info)
99 | .setPriority(NotificationCompat.PRIORITY_HIGH)
100 | .setAutoCancel(true)
101 | .setContentIntent(pendingIntent)
102 |
103 | val notificationManager = context.getSystemService(NotificationManager::class.java)
104 |
105 | notificationManager.notify(0, builder.build())
106 | }
107 |
108 | actual fun clearAppNotification() {
109 | val context: Context by inject(Context::class.java)
110 | val notificationManager =
111 | context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
112 | notificationManager.cancelAll()
113 | }
--------------------------------------------------------------------------------
/composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
14 |
18 |
24 |
30 |
36 |
--------------------------------------------------------------------------------
/composeApp/src/commonMain/kotlin/data/model/MusicScreenModel.kt:
--------------------------------------------------------------------------------
1 | package data.model
2 |
3 | import api.BaseApi
4 | import api.baseJsonConf
5 | import biz.AudioPlayer
6 | import cafe.adriel.voyager.core.model.ScreenModel
7 | import constant.enums.MusicPlayModel
8 | import constant.enums.MusicPlayScreenTabModel
9 | import data.AudioSimpleModel
10 | import data.MusicPlayerState
11 | import data.store.DataStorageManager
12 | import kotlinx.coroutines.flow.MutableStateFlow
13 | import kotlinx.coroutines.flow.asStateFlow
14 | import kotlinx.serialization.encodeToString
15 |
16 | class MusicScreenModel(
17 | private val dataStorageManager: DataStorageManager
18 | ) : ScreenModel {
19 |
20 | //fav
21 | private val _favList = MutableStateFlow(setOf())
22 | val favList = _favList.asStateFlow()
23 | fun addFav(id: String) {
24 | val newFav = mutableSetOf()
25 | newFav.addAll(_favList.value)
26 | newFav.add(id)
27 | _favList.value = newFav
28 | dataStorageManager.setString(
29 | DataStorageManager.FAV_AUDIO_ID_LIST,
30 | baseJsonConf.encodeToString(newFav)
31 | )
32 | favUpdateToPlayer()
33 | }
34 |
35 | fun delFav(id: String) {
36 | val newFav = mutableSetOf()
37 | _favList.value.forEach { if (it != id) newFav.add(it) }
38 | _favList.value = newFav
39 | dataStorageManager.setString(
40 | DataStorageManager.FAV_AUDIO_ID_LIST,
41 | baseJsonConf.encodeToString(newFav)
42 | )
43 | favUpdateToPlayer()
44 | }
45 |
46 | private fun favUpdateToPlayer() {
47 | if (_playerState.value.currentCollectionId == MusicPlayScreenTabModel.FAV.collectionId) {
48 | _player.value.clearSongs()
49 | _player.value.addSongList(_musicPlayMap.value
50 | .filter { _favList.value.contains(it.key) })
51 | }
52 | }
53 |
54 | //tab
55 | private val _musicTab = MutableStateFlow(MusicPlayScreenTabModel.COMMON)
56 | val musicTab = _musicTab.asStateFlow()
57 | fun updateMusicTab(tab: MusicPlayScreenTabModel) {
58 | _musicTab.value = tab
59 | }
60 |
61 | //player
62 | private val _playerState = MutableStateFlow(MusicPlayerState())
63 | val playerState = _playerState.asStateFlow()
64 |
65 | private val _player = MutableStateFlow(AudioPlayer(_playerState.value))
66 | private val _musicPlayMap = MutableStateFlow