├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── xml
│ │ │ │ ├── preferences_theme.xml
│ │ │ │ ├── preferences_storage.xml
│ │ │ │ ├── preferences_header.xml
│ │ │ │ ├── device_filter.xml
│ │ │ │ ├── preferences_info.xml
│ │ │ │ └── setting.xml
│ │ │ ├── values
│ │ │ │ ├── codes.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── color.xml
│ │ │ ├── drawable
│ │ │ │ ├── btn.png
│ │ │ │ ├── btn_.png
│ │ │ │ ├── next.png
│ │ │ │ ├── play.png
│ │ │ │ ├── prev.png
│ │ │ │ ├── chain.png
│ │ │ │ ├── chain_.png
│ │ │ │ ├── chain__.png
│ │ │ │ ├── next_.png
│ │ │ │ ├── pause.png
│ │ │ │ ├── pause_.png
│ │ │ │ ├── phantom.png
│ │ │ │ ├── play_.png
│ │ │ │ ├── playbg.png
│ │ │ │ ├── prev_.png
│ │ │ │ ├── chainled.png
│ │ │ │ ├── midi_lp_s.png
│ │ │ │ ├── midi_lp_x.png
│ │ │ │ ├── phantom_.png
│ │ │ │ ├── theme_add.png
│ │ │ │ ├── theme_ic.png
│ │ │ │ ├── custom_logo.png
│ │ │ │ ├── midi_lp_mini.png
│ │ │ │ ├── midi_lp_mk2.png
│ │ │ │ ├── midi_lp_mk3.png
│ │ │ │ ├── midi_lp_pro.png
│ │ │ │ ├── midi_matrix.png
│ │ │ │ ├── community_cafe.png
│ │ │ │ ├── community_mail.png
│ │ │ │ ├── community_web.png
│ │ │ │ ├── community_discord.png
│ │ │ │ ├── midi_midifighter.png
│ │ │ │ ├── community_facebook.png
│ │ │ │ ├── community_kakaotalk.png
│ │ │ │ ├── midi_master_keyboard.png
│ │ │ │ ├── community_facebook_group.png
│ │ │ │ ├── border_divider.xml
│ │ │ │ ├── border_apply_off.xml
│ │ │ │ ├── border_gray.xml
│ │ │ │ ├── border_settings.xml
│ │ │ │ ├── xml_next.xml
│ │ │ │ ├── xml_play.xml
│ │ │ │ ├── xml_prev.xml
│ │ │ │ ├── xml_pause.xml
│ │ │ │ ├── border_apply.xml
│ │ │ │ ├── border_apply_on.xml
│ │ │ │ ├── ic_delete_24dp.xml
│ │ │ │ ├── ic_music_note_24dp.xml
│ │ │ │ ├── ic_bookmark_clip_back.xml
│ │ │ │ ├── ic_info.xml
│ │ │ │ ├── ic_pad_24dp.xml
│ │ │ │ ├── ic_edit_24dp.xml
│ │ │ │ ├── ic_exit.xml
│ │ │ │ ├── ic_storage.xml
│ │ │ │ ├── ic_payment.xml
│ │ │ │ ├── ic_error.xml
│ │ │ │ ├── ic_star_border_24dp.xml
│ │ │ │ ├── ic_bookmark_on.xml
│ │ │ │ ├── ic_bookmark_off.xml
│ │ │ │ ├── ic_palette.xml
│ │ │ │ ├── ic_bookmark_clip_front.xml
│ │ │ │ ├── ic_sort_desc.xml
│ │ │ │ ├── ic_sort_asc.xml
│ │ │ │ ├── ic_youtube_24dp.xml
│ │ │ │ ├── ic_web_24dp.xml
│ │ │ │ ├── ic_led_event_24dp.xml
│ │ │ │ ├── ic_launcher_foreground.xml
│ │ │ │ └── ic_chain_24dp.xml
│ │ │ ├── font
│ │ │ │ ├── quicksand_bold.ttf
│ │ │ │ └── montserrat_regular.ttf
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── baseline_launchpad_24dp.png
│ │ │ │ ├── baseline_settings_white_24.png
│ │ │ │ ├── baseline_folder_open_white_24.png
│ │ │ │ └── baseline_shopping_basket_white_24.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── baseline_launchpad_24dp.png
│ │ │ │ ├── baseline_settings_white_24.png
│ │ │ │ ├── baseline_folder_open_white_24.png
│ │ │ │ └── baseline_shopping_basket_white_24.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── baseline_launchpad_24dp.png
│ │ │ │ ├── baseline_settings_white_24.png
│ │ │ │ ├── baseline_folder_open_white_24.png
│ │ │ │ └── baseline_shopping_basket_white_24.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ ├── baseline_launchpad_24dp.png
│ │ │ │ ├── baseline_settings_white_24.png
│ │ │ │ ├── baseline_folder_open_white_24.png
│ │ │ │ └── baseline_shopping_basket_white_24.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ │ ├── baseline_launchpad_24dp.png
│ │ │ │ ├── baseline_settings_white_24.png
│ │ │ │ ├── baseline_folder_open_white_24.png
│ │ │ │ └── baseline_shopping_basket_white_24.png
│ │ │ ├── anim
│ │ │ │ ├── activity_in.xml
│ │ │ │ ├── activity_out.xml
│ │ │ │ ├── pack_in.xml
│ │ │ │ ├── panel_in.xml
│ │ │ │ ├── panel_out.xml
│ │ │ │ └── pack_new_in.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ └── layout
│ │ │ │ ├── activity_settings.xml
│ │ │ │ ├── activity_setting_legacy.xml
│ │ │ │ ├── item_midi_device.xml
│ │ │ │ ├── include_property_verticle.xml
│ │ │ │ ├── include_property_horizontal.xml
│ │ │ │ ├── activity_theme.xml
│ │ │ │ ├── item_theme.xml
│ │ │ │ ├── item_setting.xml
│ │ │ │ ├── activity_importpack.xml
│ │ │ │ ├── activity_splash.xml
│ │ │ │ ├── fragment_main_list.xml
│ │ │ │ ├── include_property_block.xml
│ │ │ │ └── activity_store.xml
│ │ ├── ic_launcher-playstore.png
│ │ └── java
│ │ │ └── com
│ │ │ └── kimjisub
│ │ │ └── launchpad
│ │ │ ├── manager
│ │ │ ├── Constant.kt
│ │ │ ├── Functions.kt
│ │ │ ├── ColorManager.kt
│ │ │ ├── NotificationManager.kt
│ │ │ └── ChannelManager.kt
│ │ │ ├── tool
│ │ │ ├── BindUtil.kt
│ │ │ ├── splitties
│ │ │ │ ├── Browse.kt
│ │ │ │ └── LiveData.kt
│ │ │ ├── serializer
│ │ │ │ └── UriSerializer.kt
│ │ │ ├── UIManager.kt
│ │ │ ├── ArrayListExtra.kt
│ │ │ ├── LiveDataEvent.kt
│ │ │ ├── AutorunTimer.kt
│ │ │ └── Log.kt
│ │ │ ├── unipack
│ │ │ ├── struct
│ │ │ │ ├── Sound.kt
│ │ │ │ ├── LedAnimation.kt
│ │ │ │ └── AutoPlay.kt
│ │ │ └── runner
│ │ │ │ └── ChainObserver.kt
│ │ │ ├── midi
│ │ │ ├── driver
│ │ │ │ ├── Noting.kt
│ │ │ │ ├── MasterKeyboard.kt
│ │ │ │ ├── MidiFighter.kt
│ │ │ │ ├── LaunchpadMK2.kt
│ │ │ │ ├── LaunchpadS.kt
│ │ │ │ ├── LaunchpadX.kt
│ │ │ │ └── DriverRef.kt
│ │ │ └── controller
│ │ │ │ └── MidiController.kt
│ │ │ ├── activity
│ │ │ ├── ImportPackByFileActivity.kt
│ │ │ ├── StoreActivity.kt
│ │ │ ├── SettingsActivity.kt
│ │ │ ├── SplashActivity.kt
│ │ │ └── ThemeActivity.kt
│ │ │ ├── fragment
│ │ │ ├── settings
│ │ │ │ ├── ThemeFragment.kt
│ │ │ │ ├── HeaderFragment.kt
│ │ │ │ └── StorageFragment.kt
│ │ │ ├── BaseFragment.kt
│ │ │ ├── MainTotalPanelFragment.kt
│ │ │ └── MainPackPanelFragment.kt
│ │ │ ├── api
│ │ │ ├── unipad
│ │ │ │ ├── vo
│ │ │ │ │ └── UnishareVO.kt
│ │ │ │ └── UniPadApi.kt
│ │ │ ├── file
│ │ │ │ └── FileApi.kt
│ │ │ └── BaseApiService.kt
│ │ │ ├── network
│ │ │ ├── fb
│ │ │ │ ├── StoreVO.kt
│ │ │ │ └── FsStore.kt
│ │ │ └── Networks.kt
│ │ │ ├── db
│ │ │ ├── util
│ │ │ │ ├── DateConverter.kt
│ │ │ │ └── LiveDataUtil.kt
│ │ │ ├── AppDatabase.kt
│ │ │ ├── repository
│ │ │ │ └── UnipackRepository.kt
│ │ │ ├── dao
│ │ │ │ └── UnipackDao.kt
│ │ │ └── ent
│ │ │ │ └── Unipack.kt
│ │ │ ├── binding
│ │ │ ├── ImageView.kt
│ │ │ ├── IconSwitch.kt
│ │ │ └── SpinnerBindingAdapter.kt
│ │ │ ├── adapter
│ │ │ ├── DialogListAdapter.kt
│ │ │ └── ThemeAdapter.kt
│ │ │ ├── AppOpenManager.kt
│ │ │ └── BaseApplication.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── kimjisub
│ │ │ └── launchpad
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── kimjisub
│ │ └── launchpad
│ │ └── ExampleInstrumentedTest.kt
├── proguard-okhttp3.pro
├── proguard-firebase.pro
├── proguard-common.pro
├── proguard-rules.pro
└── proguard-retrofit2.pro
├── design
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable
│ │ │ │ ├── border_icon_off.xml
│ │ │ │ ├── border_no_round.xml
│ │ │ │ ├── border_icon_on.xml
│ │ │ │ ├── border_all_round.xml
│ │ │ │ ├── border_all_round_gray3.xml
│ │ │ │ ├── border_all_round_gray.xml
│ │ │ │ ├── border_right_round.xml
│ │ │ │ ├── border_icon.xml
│ │ │ │ ├── border_panel_pack.xml
│ │ │ │ ├── border_panel_total.xml
│ │ │ │ ├── ic_delete_24dp.xml
│ │ │ │ ├── ic_music_note_24dp.xml
│ │ │ │ ├── ic_bookmark_clip_back.xml
│ │ │ │ ├── ic_pad_24dp.xml
│ │ │ │ ├── ic_edit_24dp.xml
│ │ │ │ ├── ic_star_border_24dp.xml
│ │ │ │ ├── ic_bookmark_on.xml
│ │ │ │ ├── ic_bookmark_off.xml
│ │ │ │ ├── ic_bookmark_clip_front.xml
│ │ │ │ ├── ic_sort_desc.xml
│ │ │ │ ├── ic_sort_asc.xml
│ │ │ │ ├── ic_youtube_24dp.xml
│ │ │ │ ├── ic_web_24dp.xml
│ │ │ │ ├── ic_led_event_24dp.xml
│ │ │ │ ├── ic_chain_24dp.xml
│ │ │ │ └── playbtn.xml
│ │ │ ├── values
│ │ │ │ ├── styles.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── attrs.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── color.xml
│ │ │ ├── layout
│ │ │ │ ├── view_chain.xml
│ │ │ │ ├── view_pad.xml
│ │ │ │ └── view_midi_item.xml
│ │ │ └── values-ko
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── kimjisub
│ │ │ └── design
│ │ │ ├── binding
│ │ │ ├── SpinnerBindingAdapter.kt
│ │ │ └── ImageViewBindingAdapter.kt
│ │ │ ├── manage
│ │ │ ├── UIManager.kt
│ │ │ └── SyncCheckBox.kt
│ │ │ ├── panel
│ │ │ └── StoreTotalPanel.kt
│ │ │ ├── view
│ │ │ ├── MidiItemView.kt
│ │ │ ├── ChainView.kt
│ │ │ └── PadView.kt
│ │ │ └── layout
│ │ │ └── RadioButtonGroupTableLayout.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── kimjisub
│ │ │ └── design
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── kimjisub
│ │ └── design
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── keystore.properties.example
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── codeStyles
│ └── codeStyleConfig.xml
└── dictionaries
│ ├── kimjisub.xml
│ └── rlawl.xml
├── .gitignore
├── gradle.properties
├── README.md
└── gradlew.bat
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/design/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':design'
2 |
--------------------------------------------------------------------------------
/keystore.properties.example:
--------------------------------------------------------------------------------
1 | storeFile=
2 | storePassword=
3 | keyAlias=
4 | keyPassword=
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences_theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/codes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/btn.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/btn_.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/next.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/play.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/prev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/prev.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/chain.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chain_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/chain_.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chain__.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/chain__.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/next_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/next_.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/pause.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/pause_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/pause_.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/phantom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/phantom.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/play_.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/playbg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/playbg.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/prev_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/prev_.png
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/chainled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/chainled.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/midi_lp_s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/midi_lp_s.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/midi_lp_x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/midi_lp_x.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/phantom_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/phantom_.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/theme_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/theme_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/theme_ic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/theme_ic.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/custom_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/custom_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/midi_lp_mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/midi_lp_mini.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/midi_lp_mk2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/midi_lp_mk2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/midi_lp_mk3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/midi_lp_mk3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/midi_lp_pro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/midi_lp_pro.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/midi_matrix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/midi_matrix.png
--------------------------------------------------------------------------------
/app/src/main/res/font/quicksand_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/font/quicksand_bold.ttf
--------------------------------------------------------------------------------
/app/src/main/res/drawable/community_cafe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/community_cafe.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/community_mail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/community_mail.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/community_web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/community_web.png
--------------------------------------------------------------------------------
/app/src/main/res/font/montserrat_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/font/montserrat_regular.ttf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/community_discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/community_discord.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/midi_midifighter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/midi_midifighter.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/community_facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/community_facebook.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/community_kakaotalk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/community_kakaotalk.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/midi_master_keyboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/midi_master_keyboard.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/community_facebook_group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable/community_facebook_group.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/baseline_launchpad_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-hdpi/baseline_launchpad_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/baseline_launchpad_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-mdpi/baseline_launchpad_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/baseline_launchpad_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xhdpi/baseline_launchpad_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/baseline_settings_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-hdpi/baseline_settings_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/baseline_settings_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-mdpi/baseline_settings_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/baseline_settings_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xhdpi/baseline_settings_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/baseline_launchpad_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xxhdpi/baseline_launchpad_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/baseline_launchpad_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xxxhdpi/baseline_launchpad_24dp.png
--------------------------------------------------------------------------------
/app/proguard-okhttp3.pro:
--------------------------------------------------------------------------------
1 | # Begin: Proguard rules for okhttp3
2 |
3 | -dontwarn okhttp3.**
4 | -dontwarn okio.**
5 |
6 | -dontnote okhttp3.**
7 |
8 | # End: Proguard rules for okhttp3
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/baseline_folder_open_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-hdpi/baseline_folder_open_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/baseline_folder_open_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-mdpi/baseline_folder_open_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/baseline_settings_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xxhdpi/baseline_settings_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/baseline_settings_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xxxhdpi/baseline_settings_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/baseline_folder_open_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xhdpi/baseline_folder_open_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/baseline_folder_open_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xxhdpi/baseline_folder_open_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/baseline_folder_open_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xxxhdpi/baseline_folder_open_white_24.png
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/manager/Constant.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.manager
2 |
3 | object Constant {
4 | const val AUTOPLAY_AUTOMAPPING_DELAY_PRESET = -15
5 |
6 |
7 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/baseline_shopping_basket_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-hdpi/baseline_shopping_basket_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/baseline_shopping_basket_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-mdpi/baseline_shopping_basket_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/baseline_shopping_basket_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xhdpi/baseline_shopping_basket_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/baseline_shopping_basket_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xxhdpi/baseline_shopping_basket_white_24.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/baseline_shopping_basket_white_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kimjisub/unipad-android/HEAD/app/src/main/res/drawable-xxxhdpi/baseline_shopping_basket_white_24.png
--------------------------------------------------------------------------------
/.idea/dictionaries/kimjisub.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | splitties
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/tool/BindUtil.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.tool
2 |
3 | object BindUtil {
4 |
5 | fun valueOrDefault(value: T?, defaultValue: T): T {
6 | return value ?: defaultValue
7 | }
8 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_divider.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_icon_off.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_no_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/design/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/design/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_icon_on.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16sp
5 | 12sp
6 | 10sp
7 |
8 | 40dp
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_apply_off.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_gray.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_all_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_all_round_gray3.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/xml_next.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/xml_play.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/xml_prev.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_all_round_gray.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/unipack/struct/Sound.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.unipack.struct
2 |
3 | import java.io.File
4 |
5 | data class Sound(
6 | val file: File,
7 | val loop: Int,
8 | val wormhole: Int = -1,
9 | var num: Int = 0,
10 | var id: Int = -1,
11 | )
--------------------------------------------------------------------------------
/app/src/main/res/anim/activity_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/activity_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/xml_pause.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Oct 15 17:40:43 KST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_apply.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences_storage.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/design/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 14sp
5 | 20sp
6 | 17sp
7 | 10sp
8 |
9 | 40dp
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_right_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/proguard-firebase.pro:
--------------------------------------------------------------------------------
1 | # Begin: Proguard rules for Firebase
2 |
3 | # Authentication
4 | -keepattributes *Annotation*
5 |
6 | # Realtime database
7 | -keepattributes Signature
8 |
9 | -keepattributes Signature
10 | -keepclassmembers class com.kimjisub.launchpad.network.fb.* {
11 | *;
12 | }
13 |
14 | # End: Proguard rules for Firebase
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_apply_on.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_panel_pack.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/border_panel_total.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_delete_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/dictionaries/rlawl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | admob
5 | autorun
6 | btns
7 | cooltime
8 | gson
9 | kimjisub
10 | lateinit
11 | unipack
12 | unipacks
13 | unipad
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_music_note_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/midi/driver/Noting.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.midi.driver
2 |
3 | class Noting : DriverRef() {
4 | override fun getSignal(cmd: Int, sig: Int, note: Int, velocity: Int) {}
5 | override fun sendPadLed(x: Int, y: Int, velocity: Int) {}
6 | override fun sendChainLed(c: Int, velocity: Int) {}
7 | override fun sendFunctionkeyLed(f: Int, velocity: Int) {}
8 | override fun sendClearLed() {}
9 | }
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_music_note_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/pack_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/tool/splitties/Browse.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.tool.splitties
2 |
3 | import android.content.Intent
4 | import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
5 | import android.net.Uri
6 |
7 | fun android.content.Context.browse(link: String) {
8 | val myIntent = Intent(Intent.ACTION_VIEW, Uri.parse(link))
9 | myIntent.addFlags(FLAG_ACTIVITY_NEW_TASK)
10 | startActivity(myIntent)
11 | }
12 |
--------------------------------------------------------------------------------
/design/src/main/java/com/kimjisub/design/binding/SpinnerBindingAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.binding
2 |
3 | import androidx.appcompat.widget.AppCompatSpinner
4 | import androidx.databinding.BindingAdapter
5 |
6 | object SpinnerBindingAdapter {
7 |
8 | @JvmStatic
9 | @BindingAdapter("android:selectedItemPosition")
10 | fun setSelectedItemPosition(spinner: AppCompatSpinner, position: Int) {
11 | spinner.setSelection(position)
12 | }
13 | }
--------------------------------------------------------------------------------
/design/src/test/java/com/kimjisub/design/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * @see [Testing documentation](http://d.android.com/tools/testing)
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark_clip_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/test/java/com/kimjisub/launchpad/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * @see [Testing documentation](http://d.android.com/tools/testing)
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_bookmark_clip_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/activity/ImportPackByFileActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.activity
2 |
3 | import android.os.Bundle
4 |
5 | class ImportPackByFileActivity : BaseActivity() {
6 | override fun onCreate(savedInstanceState: Bundle?) {
7 | super.onCreate(savedInstanceState)
8 | // Todo
9 | // UniPackImporter(
10 | // context = this,
11 | // File(intent?.data?.path!!),
12 | // uniPackWorkspace
13 | // )
14 | finish()
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/fragment/settings/ThemeFragment.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.fragment.settings
2 |
3 | import android.os.Bundle
4 | import androidx.preference.PreferenceFragmentCompat
5 | import com.kimjisub.launchpad.R
6 |
7 | class ThemeFragment : PreferenceFragmentCompat() {
8 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
9 | setPreferencesFromResource(R.xml.preferences_theme, rootKey)
10 | }
11 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/proguard-common.pro:
--------------------------------------------------------------------------------
1 | # Begin: Common Proguard rules
2 |
3 | # Don't note duplicate definition (Legacy Apche Http Client)
4 | -dontnote android.net.http.*
5 | -dontnote org.apache.http.**
6 |
7 | # Add when compile with JDK 1.7
8 | -keepattributes EnclosingMethod
9 |
10 | # GSON
11 | -keepattributes *Annotation*
12 | -keep class com.google.gson.** { *; }
13 |
14 | -keep class com.kimjisub.launchpad.activity.MainActivity { *; }
15 |
16 |
17 | # End: Common Proguard rules
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_pad_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_pad_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_edit_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/activity/StoreActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.activity
2 |
3 | import android.os.Bundle
4 | import com.kimjisub.launchpad.databinding.ActivityStoreBinding
5 |
6 | class StoreActivity : BaseActivity() {
7 | private lateinit var b: ActivityStoreBinding
8 | override fun onCreate(savedInstanceState: Bundle?) {
9 | super.onCreate(savedInstanceState)
10 | b = ActivityStoreBinding.inflate(layoutInflater)
11 | setContentView(b.root)
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/api/unipad/vo/UnishareVO.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.api.unipad.vo
2 |
3 | data class UnishareVO(
4 | var _id: String? = null,
5 | var title: String? = null,
6 | var producer: String? = null,
7 | var content: String? = null,
8 | var website: String? = null,
9 | var youtube: String? = null,
10 | var fileSize: Long = 0,
11 | var isPublic: Boolean = false,//todo remove is
12 | var password: String? = null,
13 | var downloadCount: Int = 0,
14 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_exit.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_edit_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/network/fb/StoreVO.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.network.fb
2 |
3 | import com.google.firebase.database.IgnoreExtraProperties
4 |
5 | @IgnoreExtraProperties
6 | data class StoreVO(
7 | var code: String? = null,
8 | var title: String? = null,
9 | var producerName: String? = null,
10 | @JvmField
11 | var isAutoPlay: Boolean = false,
12 | @JvmField
13 | var isLED: Boolean = false,
14 | var downloadCount: Int = 0,
15 | var URL: String? = null,
16 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/tool/splitties/LiveData.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.tool.splitties
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MediatorLiveData
5 | import androidx.lifecycle.MutableLiveData
6 |
7 | fun LiveData.ignoreFirst(): MutableLiveData {
8 | val result = MediatorLiveData()
9 | var isFirst = true
10 | result.addSource(this) {
11 | if (isFirst) isFirst = false
12 | else result.value = it
13 | }
14 | return result
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/fragment/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.fragment
2 |
3 | import androidx.fragment.app.Fragment
4 | import com.kimjisub.launchpad.manager.PreferenceManager
5 | import com.kimjisub.launchpad.manager.WorkspaceManager
6 | import org.koin.android.ext.android.inject
7 |
8 | open class BaseFragment : Fragment() {
9 | val p: PreferenceManager by inject()
10 | val ws: WorkspaceManager by inject()
11 | // val unipackRepo: UnipackRepository by inject()
12 |
13 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_storage.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_payment.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
13 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/db/util/DateConverter.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.db.util
2 |
3 | import androidx.room.TypeConverter
4 | import java.util.Date
5 |
6 | // https://developer.android.com/training/data-storage/room/referencing-data?hl=ko
7 |
8 | class DateConverter {
9 | @TypeConverter
10 | fun fromTimestamp(value: Long?): Date? {
11 | return value?.let { Date(it) }
12 | }
13 |
14 | @TypeConverter
15 | fun dateToTimestamp(date: Date?): Long? {
16 | return date?.time?.toLong()
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_error.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_border_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/midi/controller/MidiController.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.midi.controller
2 |
3 | abstract class MidiController {
4 |
5 | abstract fun onAttach()
6 |
7 | abstract fun onDetach()
8 |
9 | abstract fun onPadTouch(x: Int, y: Int, upDown: Boolean, velocity: Int)
10 |
11 | abstract fun onFunctionKeyTouch(f: Int, upDown: Boolean)
12 |
13 | abstract fun onChainTouch(c: Int, upDown: Boolean)
14 |
15 | abstract fun onUnknownEvent(cmd: Int, sig: Int, note: Int, velocity: Int)
16 | }
17 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_star_border_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/unipack/struct/LedAnimation.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.unipack.struct
2 |
3 | class LedAnimation(
4 | val ledEvents: ArrayList,
5 | val loop: Int,
6 | val num: Int,
7 | ) {
8 | interface LedEvent {
9 | class On(
10 | val x: Int,
11 | val y: Int,
12 | val color: Int = -1,
13 | val velocity: Int = 4,
14 | ) : LedEvent
15 |
16 | class Off(
17 | val x: Int,
18 | val y: Int,
19 | ) : LedEvent
20 |
21 | class Delay(
22 | val delay: Int,
23 | ) : LedEvent
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/panel_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
9 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/panel_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
9 |
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/unipack/struct/AutoPlay.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.unipack.struct
2 |
3 | class AutoPlay(
4 | val elements: ArrayList,
5 | ) {
6 | interface Element {
7 | class On(
8 | val x: Int,
9 | val y: Int,
10 | val currChain: Int,
11 | val num: Int,
12 | ) : Element
13 |
14 | class Off(
15 | val x: Int,
16 | val y: Int,
17 | val currChain: Int,
18 | ) : Element
19 |
20 | class Chain(
21 | val c: Int,
22 | ) : Element
23 |
24 | class Delay(
25 | var delay: Int,
26 | val currChain: Int,
27 | ) : Element
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/pack_new_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark_on.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_bookmark_on.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/tool/serializer/UriSerializer.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.tool.serializer
2 |
3 | import android.net.Uri
4 | import kotlinx.serialization.KSerializer
5 | import kotlinx.serialization.Serializer
6 | import kotlinx.serialization.encoding.Decoder
7 | import kotlinx.serialization.encoding.Encoder
8 |
9 | @Serializer(forClass = Uri::class)
10 | object UriSerializer : KSerializer {
11 | override fun deserialize(decoder: Decoder): Uri {
12 | return Uri.parse(decoder.decodeString())
13 | }
14 |
15 | override fun serialize(encoder: Encoder, value: Uri) {
16 | encoder.encodeString(value.toString())
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/binding/ImageView.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.binding
2 |
3 | import android.graphics.drawable.Drawable
4 | import android.widget.ImageView
5 | import androidx.databinding.BindingAdapter
6 |
7 | @BindingAdapter("imgRes")
8 | fun imgRes(imageView: ImageView, resId: Int?) {
9 | if (resId != null)
10 | imageView.setImageResource(resId)
11 | else
12 | imageView.setImageDrawable(null)
13 |
14 | }
15 |
16 | @BindingAdapter("imgRes")
17 | fun imgRes(imageView: ImageView, drawable: Drawable?) {
18 | if (drawable != null)
19 | imageView.setImageDrawable(drawable)
20 | else
21 | imageView.setImageDrawable(null)
22 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark_off.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_bookmark_off.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/tool/UIManager.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.tool
2 |
3 | import android.content.Context
4 | import android.util.DisplayMetrics
5 |
6 | object UIManager {
7 | fun pxToDp(context: Context, pixel: Int): Int {
8 | var dp = 0f
9 | try {
10 | val metrics: DisplayMetrics = context.resources.displayMetrics
11 | dp = pixel / (metrics.densityDpi / 160f)
12 | } catch (e: Exception) {
13 | }
14 | return dp.toInt()
15 | }
16 |
17 | fun dpToPx(context: Context, dp: Float): Int {
18 | val metrics: DisplayMetrics = context.resources.displayMetrics
19 | val px = dp * (metrics.densityDpi / 160f)
20 | return Math.round(px)
21 | }
22 | }
--------------------------------------------------------------------------------
/design/src/main/java/com/kimjisub/design/manage/UIManager.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.manage
2 |
3 | import android.content.Context
4 | import android.util.DisplayMetrics
5 |
6 | object UIManager {
7 | fun pxToDp(context: Context, pixel: Int): Int {
8 | var dp = 0f
9 | try {
10 | val metrics: DisplayMetrics = context.resources.displayMetrics
11 | dp = pixel / (metrics.densityDpi / 160f)
12 | } catch (e: Exception) {
13 | }
14 | return dp.toInt()
15 | }
16 |
17 | fun dpToPx(context: Context, dp: Float): Int {
18 | val metrics: DisplayMetrics = context.resources.displayMetrics
19 | val px = dp * (metrics.densityDpi / 160f)
20 | return Math.round(px)
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/manager/Functions.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.manager
2 |
3 | import android.app.Activity
4 | import android.content.ClipData
5 | import android.content.ClipboardManager
6 | import android.content.Context
7 | import androidx.fragment.app.Fragment
8 |
9 | fun Context.putClipboard(text: String) {
10 | val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
11 | val clip: ClipData = ClipData.newPlainText("UniPad", text)
12 | clipboard.setPrimaryClip(clip)
13 | }
14 |
15 | fun Activity.putClipboard(text: String) {
16 | baseContext.putClipboard(text)
17 | }
18 |
19 | fun Fragment.putClipboard(text: String) {
20 | requireContext().putClipboard(text)
21 | }
22 |
--------------------------------------------------------------------------------
/design/src/main/java/com/kimjisub/design/binding/ImageViewBindingAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.binding
2 |
3 | import android.graphics.drawable.Drawable
4 | import android.widget.ImageView
5 | import androidx.databinding.BindingAdapter
6 |
7 | object ImageViewBindingAdapter {
8 | @JvmStatic
9 | @BindingAdapter("imgRes")
10 | fun imgRes(imageView: ImageView, resId: Int?) {
11 | if (resId != null)
12 | imageView.setImageResource(resId)
13 | else
14 | imageView.setImageDrawable(null)
15 |
16 | }
17 |
18 | @JvmStatic
19 | @BindingAdapter("imgRes")
20 | fun imgRes(imageView: ImageView, drawable: Drawable?) {
21 | if (drawable != null)
22 | imageView.setImageDrawable(drawable)
23 | else
24 | imageView.setImageDrawable(null)
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_setting_legacy.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/kimjisub/launchpad/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.runner.AndroidJUnit4
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * @see [Testing documentation](http://d.android.com/tools/testing)
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.kimjisub.launchpad", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/design/src/androidTest/java/com/kimjisub/design/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.runner.AndroidJUnit4
5 | import org.junit.Assert.assertEquals
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | /**
10 | * Instrumented test, which will execute on an Android device.
11 | *
12 | * @see [Testing documentation](http://d.android.com/tools/testing)
13 | */
14 | @RunWith(AndroidJUnit4::class)
15 | class ExampleInstrumentedTest {
16 | @Test
17 | fun useAppContext() {
18 | // Context of the app under test.
19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
20 | assertEquals("com.kimjisub.design.test", appContext.packageName)
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/tool/ArrayListExtra.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.extra
2 |
3 | import androidx.databinding.Observable
4 |
5 |
6 | fun T.addOnPropertyChanged(callback: (T) -> Unit) =
7 | addOnPropertyChangedCallback(
8 | object : Observable.OnPropertyChangedCallback() {
9 | override fun onPropertyChanged(observable: Observable?, i: Int) =
10 | callback(observable as T)
11 | })
12 |
13 | /**
14 | * Be sure the array is sort by the comparator you provided.
15 | * */
16 | fun ArrayList.getVirtualIndexFormSorted(comparator: Comparator, target: T): Int {
17 | var index = 0
18 | for ((i, item: T) in this.withIndex()) {
19 | if (comparator.compare(target, item) < 0) {
20 | index = i
21 | break
22 | }
23 | }
24 | return index
25 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | #*.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | build/
18 | /*/build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log files
27 | *.log
28 |
29 | # Android Studio files
30 | # .idea/
31 | .idea/*.*
32 | .idea/caches/
33 | .idea/libraries/
34 | .idea/modules/
35 | *.iml
36 |
37 | # Android Studio Navigation editor temp files
38 | .navigation/
39 |
40 | # Android Studio captures folder
41 | captures/
42 | .DS_Store
43 |
44 | **/ndkHelperBin
45 | **/.cxx
46 | *.jks
47 | /app/release/app-release.aab
48 | keystore.properties
49 |
50 | app/release
--------------------------------------------------------------------------------
/design/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/network/fb/FsStore.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.network.fb
2 |
3 | import com.google.firebase.database.IgnoreExtraProperties
4 | import java.util.Date
5 |
6 | @IgnoreExtraProperties
7 | class FsStore {
8 | var chainCount: Long = 0
9 | var code: String? = null
10 | var description: String? = null
11 | var difficulty: Long = 0
12 | var downloadCount: Long = 0
13 |
14 | @JvmField
15 | var isAutoPlay = false
16 |
17 | @JvmField
18 | var isLed = false
19 |
20 | @JvmField
21 | var isNew = false
22 |
23 | @JvmField
24 | var isProLight = false
25 |
26 | @JvmField
27 | var isWormhole = false
28 | var playTime: Long = 0
29 | var producerName: String? = null
30 | var rank: Long = 0
31 | var title: String? = null
32 | var uploadAt: Date? = null
33 | var url: String? = null
34 | var website: String? = null
35 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_palette.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/design/src/main/java/com/kimjisub/design/panel/StoreTotalPanel.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.panel
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.LayoutInflater
6 | import android.widget.RelativeLayout
7 | import com.kimjisub.design.R.styleable
8 | import com.kimjisub.design.databinding.PanelStoreTotalBinding
9 |
10 | class StoreTotalPanel
11 | @JvmOverloads constructor(
12 | context: Context,
13 | attrs: AttributeSet? = null,
14 | defStyleAttr: Int = 0,
15 | ) : RelativeLayout(context, attrs, defStyleAttr) {
16 | val b: PanelStoreTotalBinding =
17 | PanelStoreTotalBinding.inflate(LayoutInflater.from(context), this, true)
18 |
19 | init {
20 | attrs?.let {
21 | val typedArray =
22 | context.obtainStyledAttributes(it, styleable.TotalPanel, defStyleAttr, 0)
23 |
24 | // code
25 |
26 | typedArray.recycle()
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/tool/LiveDataEvent.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.tool
2 |
3 | import androidx.lifecycle.LifecycleOwner
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.Observer
7 |
8 | open class Event(value: T) {
9 |
10 | var value = value
11 | private set
12 |
13 | private var isAlreadyHandled = false
14 |
15 | fun isActive(): Boolean = if (isAlreadyHandled) {
16 | false
17 | } else {
18 | isAlreadyHandled = true
19 | true
20 | }
21 | }
22 |
23 | fun LiveData>.observeEvent(owner: LifecycleOwner, observer: Observer) =
24 | observe(owner) {
25 | if (it.isActive()) {
26 | observer.onChanged(it.value)
27 | }
28 | }
29 |
30 | fun MutableLiveData>.emit() = postValue(Event(Unit))
31 |
32 | fun MutableLiveData>.emit(value: T) = postValue(Event(value))
--------------------------------------------------------------------------------
/design/src/main/res/layout/view_chain.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
11 |
12 |
16 |
17 |
21 |
22 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/db/util/LiveDataUtil.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.db.util
2 |
3 | import androidx.lifecycle.LifecycleOwner
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.Observer
6 |
7 | fun LiveData.observeOnce(observer: Observer) {
8 | observeForever(object : Observer {
9 | override fun onChanged(t: T) {
10 | observer.onChanged(t)
11 | removeObserver(this)
12 | }
13 | })
14 | }
15 |
16 | fun LiveData.observeRealChange(
17 | owner: LifecycleOwner,
18 | realChangeObserver: Observer,
19 | clone: (T) -> T,
20 | ): Observer {
21 | val observer = object : Observer {
22 | var prev: T? = null
23 |
24 | override fun onChanged(it: T) {
25 | if (prev != it) {
26 | realChangeObserver.onChanged(it)
27 | prev = clone(it)
28 | }
29 | }
30 | }
31 | observe(owner, observer)
32 |
33 | return observer
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/binding/IconSwitch.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.binding
2 |
3 | import androidx.databinding.BindingAdapter
4 | import androidx.databinding.InverseBindingAdapter
5 | import androidx.databinding.InverseBindingListener
6 | import com.polyak.iconswitch.IconSwitch
7 |
8 | @BindingAdapter("checkedBoolean")
9 | fun setChecked(view: IconSwitch, checked: Boolean) {
10 | view.checked = if (checked) IconSwitch.Checked.RIGHT else IconSwitch.Checked.LEFT
11 | }
12 |
13 | @BindingAdapter("checkedBooleanAttrChanged")
14 | fun setCheckedListeners(
15 | view: IconSwitch,
16 | attrChange: InverseBindingListener,
17 | ) {
18 | view.setCheckedChangeListener {
19 | attrChange.onChange()
20 | }
21 | }
22 |
23 | @InverseBindingAdapter(attribute = "checkedBoolean", event = "checkedBooleanAttrChanged")
24 | fun getChecked(view: IconSwitch): Boolean {
25 | return view.checked == IconSwitch.Checked.RIGHT
26 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark_clip_front.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
24 |
25 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_bookmark_clip_front.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sort_desc.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
14 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_sort_desc.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
14 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sort_asc.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
14 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_sort_asc.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
14 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/unipack/runner/ChainObserver.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.unipack.runner
2 |
3 | class ChainObserver {
4 | var range: IntRange = Integer.MIN_VALUE..Integer.MAX_VALUE
5 | var value: Int = 0
6 | set(value) {
7 | val realValue =
8 | when {
9 | range.first > value -> range.first
10 | range.last < value -> range.last
11 | else -> value
12 | }
13 |
14 | val prev = field
15 | field = realValue
16 | refresh(field, prev)
17 | }
18 |
19 | private val observerList: ArrayList<(curr: Int, prev: Int) -> Unit> = ArrayList()
20 |
21 | fun refresh(curr: Int = value, prev: Int = value) {
22 | for (observer in observerList)
23 | observer.invoke(curr, prev)
24 | }
25 |
26 | fun addObserver(observer: (curr: Int, prev: Int) -> Unit) = observerList.add(observer)
27 |
28 | fun removeObserver(observer: (curr: Int, prev: Int) -> Unit) = observerList.remove(observer)
29 |
30 | fun clearObserver() = observerList.clear()
31 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_youtube_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_youtube_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/design/src/main/java/com/kimjisub/design/view/MidiItemView.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.LayoutInflater
6 | import android.widget.RelativeLayout
7 | import com.kimjisub.design.R.styleable
8 | import com.kimjisub.design.databinding.ViewMidiItemBinding
9 |
10 | class MidiItemView
11 | @JvmOverloads constructor(
12 | context: Context,
13 | attrs: AttributeSet? = null,
14 | defStyleAttr: Int = 0,
15 | ) : RelativeLayout(context, attrs, defStyleAttr) {
16 | private val b: ViewMidiItemBinding =
17 | ViewMidiItemBinding.inflate(LayoutInflater.from(context), this, true)
18 |
19 | init {
20 | attrs?.let {
21 | val typedArray =
22 | context.obtainStyledAttributes(it, styleable.MidiItemView, defStyleAttr, 0)
23 |
24 | b.title = typedArray.getString(styleable.MidiItemView_title)
25 | b.subscription = typedArray.getString(styleable.MidiItemView_subscription)
26 |
27 | typedArray.recycle()
28 | }
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_midi_device.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
17 |
18 |
24 |
25 |
26 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/adapter/DialogListAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.BaseAdapter
7 | import com.kimjisub.launchpad.R.layout
8 | import com.kimjisub.launchpad.databinding.ItemSettingBinding
9 |
10 | data class DialogListItem(
11 | val title: String,
12 | val subtitle: String,
13 | val iconResId: Int? = null,
14 | )
15 |
16 |
17 | class DialogListAdapter(
18 | private val list: Array,
19 | ) : BaseAdapter() {
20 |
21 | override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
22 | val view = LayoutInflater.from(parent.context).inflate(layout.item_setting, parent, false)
23 | val bind = ItemSettingBinding.bind(view)
24 |
25 | val item = list[position]
26 |
27 | bind.data = item
28 |
29 | return bind.root
30 | }
31 |
32 | override fun getCount() = list.size
33 |
34 | override fun getItem(position: Int) = list[position].title
35 |
36 | override fun getItemId(position: Int) = position.toLong()
37 |
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/db/AppDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.db
2 |
3 | import android.content.Context
4 | import androidx.room.Database
5 | import androidx.room.Room
6 | import androidx.room.RoomDatabase
7 | import androidx.room.TypeConverters
8 | import com.kimjisub.launchpad.db.dao.UnipackDao
9 | import com.kimjisub.launchpad.db.ent.Unipack
10 | import com.kimjisub.launchpad.db.util.DateConverter
11 |
12 | @TypeConverters(DateConverter::class)
13 | @Database(entities = [Unipack::class], version = 2)
14 | abstract class AppDatabase : RoomDatabase() {
15 | abstract fun unipackDAO(): UnipackDao
16 |
17 | companion object {
18 | private var INSTANCE: AppDatabase? = null
19 |
20 | fun getInstance(context: Context): AppDatabase? {
21 | if (INSTANCE == null) {
22 | synchronized(AppDatabase::class) {
23 | INSTANCE = Room.databaseBuilder(
24 | context.applicationContext,
25 | AppDatabase::class.java, "UniPad.db"
26 | ).fallbackToDestructiveMigration().build()
27 | }
28 | }
29 | return INSTANCE
30 | }
31 |
32 | fun destroyInstance() {
33 | INSTANCE = null
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/app/src/main/res/xml/device_filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/design/src/main/res/layout/view_pad.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
11 |
12 |
16 |
17 |
21 |
22 |
30 |
31 |
37 |
38 |
--------------------------------------------------------------------------------
/design/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/midi/driver/MasterKeyboard.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.midi.driver
2 |
3 | class MasterKeyboard : DriverRef() {
4 | companion object;
5 |
6 | override fun getSignal(cmd: Int, sig: Int, note: Int, velocity: Int) {
7 | val x: Int
8 | val y: Int
9 | if (cmd == 9) {
10 | if (note in 36..67) {
11 | x = (67 - note) / 4 + 1
12 | y = 4 - (67 - note) % 4
13 | onPadTouch(x - 1, y - 1, velocity != 0, velocity)
14 | } else if (note in 68..99) {
15 | x = (99 - note) / 4 + 1
16 | y = 8 - (99 - note) % 4
17 | onPadTouch(x - 1, y - 1, velocity != 0, velocity)
18 | }
19 | } else if (velocity == 0) {
20 | if (note in 36..67) {
21 | x = (67 - note) / 4 + 1
22 | y = 4 - (67 - note) % 4
23 | onPadTouch(x - 1, y - 1, false, 0)
24 | } else if (note in 68..99) {
25 | x = (99 - note) / 4 + 1
26 | y = 8 - (99 - note) % 4
27 | onPadTouch(x - 1, y - 1, false, 0)
28 | }
29 | }
30 | }
31 |
32 | override fun sendPadLed(x: Int, y: Int, velocity: Int) {}
33 | override fun sendChainLed(c: Int, velocity: Int) {}
34 | override fun sendFunctionkeyLed(f: Int, velocity: Int) {}
35 | override fun sendClearLed() {}
36 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/db/repository/UnipackRepository.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.db.repository
2 |
3 | import androidx.lifecycle.LiveData
4 | import com.kimjisub.launchpad.db.dao.UnipackDao
5 | import com.kimjisub.launchpad.db.ent.Unipack
6 | import java.util.Date
7 |
8 | class UnipackRepository(
9 | private val unipackDao: UnipackDao,
10 | ) {
11 | fun find(id: String): LiveData {
12 | return unipackDao.find(id)
13 | }
14 |
15 | suspend fun getOrCreate(id: String): LiveData {
16 | val unipack = unipackDao.find(id).value
17 | if (unipack == null) {
18 | unipackDao.insert(Unipack.create(id))
19 | }
20 | return unipackDao.find(id)
21 | }
22 |
23 | suspend fun toggleBookmark(id: String) {
24 | unipackDao.toggleBookmark(id)
25 | }
26 |
27 | fun totalOpenCount(): LiveData {
28 | return unipackDao.totalOpenCount()
29 | }
30 |
31 | fun openCount(id: String): LiveData {
32 | return unipackDao.openCount(id)
33 | }
34 |
35 | fun lastOpenedAt(id: String): LiveData {
36 | return unipackDao.lastOpenedAt(id)
37 | }
38 |
39 | suspend fun recordOpen(id: String) {
40 | unipackDao.addOpenCount(id)
41 | unipackDao.setLastOpenedAt(id, Date())
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_web_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
12 |
13 |
18 |
22 |
23 |
26 |
30 |
31 |
35 |
36 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_web_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/tool/AutorunTimer.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.tool
2 |
3 | import java.util.Timer
4 | import java.util.TimerTask
5 |
6 | class AutorunTimer(val listener: OnListener, val timeout: Long) {
7 | private val everySecTimer = Timer()
8 | private val timeoutTimer = Timer()
9 | private var elapsedTime: Long = 0
10 | var running = false
11 |
12 | interface OnListener {
13 | fun onEverySec(leftTime: Long, elapsedTime: Long)
14 | fun onTimeOut()
15 | fun onCanceled()
16 | }
17 |
18 | fun start() {
19 | running = true
20 | everySecTimer.schedule(object : TimerTask() {
21 | override fun run() {
22 | listener.onEverySec(timeout - elapsedTime, elapsedTime)
23 | elapsedTime += 1000
24 | }
25 |
26 | }, 0, 1000)
27 |
28 | timeoutTimer.schedule(object : TimerTask() {
29 | override fun run() {
30 | timeout()
31 | }
32 | }, timeout)
33 | }
34 |
35 | fun cancel() {
36 | if (running) {
37 | running = false
38 | timeoutTimer.cancel()
39 | everySecTimer.cancel()
40 | listener.onCanceled()
41 | }
42 | }
43 |
44 | fun timeout() {
45 | if (running) {
46 | running = false
47 | timeoutTimer.cancel()
48 | everySecTimer.cancel()
49 | listener.onTimeOut()
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/binding/SpinnerBindingAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.binding
2 |
3 | import android.view.View
4 | import android.widget.AdapterView
5 | import androidx.appcompat.widget.AppCompatSpinner
6 | import androidx.databinding.BindingAdapter
7 | import androidx.databinding.InverseBindingAdapter
8 | import androidx.databinding.InverseBindingListener
9 |
10 | @BindingAdapter("selectedItemPosition")
11 | fun setSelectedItemPosition(spinner: AppCompatSpinner, position: Int) {
12 | spinner.setSelection(position)
13 | }
14 |
15 | @BindingAdapter("selectedItemPositionAttrChanged")
16 | fun selectedItemPositionListeners(
17 | spinner: AppCompatSpinner,
18 | attrChange: InverseBindingListener,
19 | ) {
20 | spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
21 | override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
22 | attrChange.onChange()
23 | }
24 |
25 | override fun onNothingSelected(p0: AdapterView<*>?) {
26 | }
27 | }
28 | }
29 |
30 | @InverseBindingAdapter(
31 | attribute = "selectedItemPosition",
32 | event = "selectedItemPositionAttrChanged"
33 | )
34 | fun getSelectedItemPosition(spinner: AppCompatSpinner): Int {
35 | return spinner.selectedItemPosition
36 | }
--------------------------------------------------------------------------------
/app/src/main/res/xml/setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
12 |
15 |
16 |
17 |
18 |
19 |
22 |
25 |
28 |
31 |
35 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/AppOpenManager.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad
2 |
3 | import android.app.Activity
4 | import android.app.Application
5 | import android.os.Bundle
6 | import androidx.lifecycle.LifecycleObserver
7 | import androidx.lifecycle.ProcessLifecycleOwner
8 |
9 |
10 | class AppOpenManager(
11 | val application: BaseApplication,
12 | ) : LifecycleObserver, Application.ActivityLifecycleCallbacks {
13 |
14 | private var currentActivity: Activity? = null
15 |
16 |
17 | init {
18 | application.registerActivityLifecycleCallbacks(this)
19 | ProcessLifecycleOwner.get().lifecycle.addObserver(this)
20 | }
21 |
22 |
23 | // Activity
24 |
25 | override fun onActivityCreated(activity: Activity, p1: Bundle?) {
26 | }
27 |
28 | override fun onActivityStarted(activity: Activity) {
29 | currentActivity = activity
30 | }
31 |
32 | override fun onActivityResumed(activity: Activity) {
33 | currentActivity = activity
34 | }
35 |
36 | override fun onActivityPaused(activity: Activity) {
37 | }
38 |
39 | override fun onActivityStopped(activity: Activity) {
40 | }
41 |
42 | override fun onActivitySaveInstanceState(activity: Activity, p1: Bundle) {
43 | }
44 |
45 | override fun onActivityDestroyed(activity: Activity) {
46 | currentActivity = null
47 | }
48 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | #-keepattributes Signature
24 | #-keepclassmembers class com.kimjisub.launchpad.networks.fb.** {
25 | # *;
26 | #}
27 | #-keepclassmembers class com.kimjisub.launchpad.manage.network.** {
28 | # *;
29 | # }
30 | #-keep class android.support.v8.renderscript.** { *; }
31 |
32 | # Coroutine
33 | -keepclassmembernames class kotlinx.* {
34 | volatile ;
35 | }
36 |
37 |
38 | # todo fix this
39 | -keep class com.kimjisub.launchpad.viewmodel.**{ *; }
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
20 |
21 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/design/src/main/res/layout/view_midi_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
16 |
17 |
18 |
19 |
24 |
25 |
32 |
33 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/include_property_verticle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
16 |
17 |
18 |
28 |
29 |
30 |
37 |
38 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/include_property_horizontal.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
16 |
17 |
18 |
28 |
29 |
30 |
37 |
38 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | #android.enableAapt2=false
10 | org.gradle.jvmargs=-Xmx1536m
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | # AndroidX package structure to make it clearer which packages are bundled with the
16 | # Android operating system, and which are packaged with your app's APK
17 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
18 | android.useAndroidX=true
19 | # Automatically convert third-party libraries to use AndroidX
20 | android.enableJetifier=true
21 | # Kotlin code style for this project: "official" or "obsolete":
22 | kotlin.code.style=official
23 | org.gradle.caching=true
24 | android.defaults.buildfeatures.buildconfig=true
25 | android.nonTransitiveRClass=false
26 | android.nonFinalResIds=false
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
17 |
18 |
24 |
25 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/design/src/main/res/values-ko/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | %1$tY-%1$tm-%1$td
4 |
5 |
6 | 유니팩 개수
7 | 유니팩 용량
8 | 플레이 횟수
9 | 테마
10 |
11 | - 제목
12 | - 제작자
13 | - 플레이 횟수
14 | - 최근 연 날짜
15 | - 다운로드 날짜
16 |
17 |
18 |
19 | 패드 크기
20 | 체인
21 | 사운드 파일
22 | Led 이벤트
23 | 용량
24 | 플레이 횟수
25 | 다운로드한 날짜
26 | 최근 플레이
27 | -
28 |
29 |
30 | 유니팩 개수
31 | 다운로드
32 |
33 |
34 | 다운로드 수
35 |
36 |
37 | 확인
38 | 폴더를 읽을 수 없습니다.
39 | 파일을 읽을 수 없습니다.
40 | MB
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/fragment/settings/HeaderFragment.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.fragment.settings
2 |
3 | import android.os.Bundle
4 | import androidx.preference.Preference
5 | import androidx.preference.PreferenceFragmentCompat
6 | import com.kimjisub.launchpad.R
7 |
8 | class HeaderFragment(val callback: (Category) -> Unit) : PreferenceFragmentCompat() {
9 | private val infoPreference: Preference by lazy { findPreference("info")!! }
10 | private val storagePreference: Preference by lazy { findPreference("storage")!! }
11 | private val themePreference: Preference by lazy { findPreference("theme")!! }
12 |
13 | private val preferences by lazy {
14 | arrayOf(infoPreference, storagePreference, themePreference)
15 | }
16 |
17 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
18 | setPreferencesFromResource(R.xml.preferences_header, rootKey)
19 |
20 | select = 0
21 | preferences.forEachIndexed { index, preference ->
22 | preference.setOnPreferenceClickListener {
23 | select = index
24 | true
25 | }
26 | }
27 | }
28 |
29 | var select: Int = 0
30 | set(value) {
31 | field = value
32 | preferences.forEachIndexed { index, preference ->
33 | if (field == index) {
34 | callback(Category.valueOf(preference.key.uppercase()))
35 | }
36 | }
37 | }
38 |
39 | companion object {
40 | enum class Category(val key: String) {
41 | INFO("info"), STORAGE("storage"), THEME("theme")
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/api/file/FileApi.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.api.file
2 |
3 | import com.kimjisub.launchpad.api.BaseApiService
4 | import com.kimjisub.launchpad.tool.Log
5 | import okhttp3.OkHttpClient
6 | import okhttp3.ResponseBody
7 | import okhttp3.logging.HttpLoggingInterceptor
8 | import okhttp3.logging.HttpLoggingInterceptor.Level
9 | import okhttp3.logging.HttpLoggingInterceptor.Logger
10 | import retrofit2.Call
11 | import retrofit2.Retrofit
12 | import retrofit2.Retrofit.Builder
13 | import retrofit2.converter.gson.GsonConverterFactory
14 | import retrofit2.http.GET
15 | import retrofit2.http.Streaming
16 | import retrofit2.http.Url
17 |
18 | class FileApi : BaseApiService() {
19 |
20 | companion object {
21 | private const val URL = "https://api.unipad.io"
22 |
23 | val service: FileService by lazy {
24 | val httpLoggingInterceptor = HttpLoggingInterceptor { message -> Log.network(message) }
25 | httpLoggingInterceptor.level = Level.BODY
26 | val client: OkHttpClient = unsafeOkHttpClient
27 | .addInterceptor(httpLoggingInterceptor)
28 | .build()
29 | val retrofit: Retrofit = Builder()
30 | .baseUrl(URL)
31 | .addConverterFactory(GsonConverterFactory.create(gson))
32 | .client(client)
33 | .build()
34 | retrofit.create(FileService::class.java)
35 | }
36 |
37 | interface FileService {
38 |
39 | // unishare
40 |
41 | @GET
42 | @Streaming
43 | fun download(@Url url: String): Call
44 | }
45 |
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/midi/driver/MidiFighter.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.midi.driver
2 |
3 | class MidiFighter : DriverRef() {
4 | companion object;
5 |
6 | override fun getSignal(cmd: Int, sig: Int, note: Int, velocity: Int) {
7 | val x: Int
8 | val y: Int
9 | if (cmd == 9) {
10 | if (note in 36..67) {
11 | x = (67 - note) / 4 + 1
12 | y = 4 - (67 - note) % 4
13 | onPadTouch(x - 1, y - 1, true, velocity)
14 | } else if (note in 68..99) {
15 | x = (99 - note) / 4 + 1
16 | y = 8 - (99 - note) % 4
17 | onPadTouch(x - 1, y - 1, true, velocity)
18 | }
19 | } else if (cmd == 8) {
20 | if (note in 36..67) {
21 | x = (67 - note) / 4 + 1
22 | y = 4 - (67 - note) % 4
23 | onPadTouch(x - 1, y - 1, false, velocity)
24 | } else if (note in 68..99) {
25 | x = (99 - note) / 4 + 1
26 | y = 8 - (99 - note) % 4
27 | onPadTouch(x - 1, y - 1, false, velocity)
28 | }
29 | }
30 | }
31 |
32 | override fun sendPadLed(x: Int, y: Int, velocity: Int) {
33 | var x = x
34 | var y = y
35 | x += 1
36 | y += 1
37 | if (y in 1..4)
38 | sendSignal(9, -110, -4 * x + y + 67, velocity) else if (y in 5..8) sendSignal(
39 | 9,
40 | -110,
41 | -4 * x + y + 95,
42 | velocity
43 | )
44 | }
45 |
46 | override fun sendChainLed(c: Int, velocity: Int) {}
47 | override fun sendFunctionkeyLed(f: Int, velocity: Int) {}
48 | override fun sendClearLed() {
49 | for (i in 0..7)
50 | for (j in 0..7)
51 | sendPadLed(i, j, 0)
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/db/dao/UnipackDao.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.db.dao
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.room.Dao
5 | import androidx.room.Insert
6 | import androidx.room.OnConflictStrategy
7 | import androidx.room.Query
8 | import com.kimjisub.launchpad.db.ent.Unipack
9 | import java.util.*
10 |
11 | @Dao
12 | interface UnipackDao {
13 | // Get
14 |
15 | @Query("SELECT * FROM Unipack WHERE id=:id")
16 | fun find(id: String): LiveData
17 |
18 | @Query("SELECT SUM(openCount) FROM Unipack")
19 | fun totalOpenCount(): LiveData
20 |
21 | @Query("SELECT MAX(lastOpenedAt) FROM Unipack")
22 | fun lastOpenedAt(): LiveData
23 |
24 | // Update
25 |
26 | @Insert(onConflict = OnConflictStrategy.IGNORE)
27 | fun insert(item: Unipack): Long
28 |
29 | @Query("UPDATE Unipack SET openCount = openCount + 1 WHERE id=:id")
30 | fun addOpenCount(id: String): Int
31 |
32 | @Query("UPDATE Unipack SET lastOpenedAt=:lastOpenedAt WHERE id=:id")
33 | fun setLastOpenedAt(id: String, lastOpenedAt: Date): Int
34 |
35 | @Query("UPDATE Unipack SET bookmark=NOT(bookmark) WHERE id=:id")
36 | fun toggleBookmark(id: String): Int
37 |
38 | @Query("SELECT openCount FROM Unipack WHERE id=:id")
39 | fun openCount(id: String): LiveData
40 |
41 | @Query("SELECT openCount FROM Unipack WHERE id=:id")
42 | fun openCountSync(id: String): Long
43 |
44 | @Query("SELECT lastOpenedAt FROM Unipack WHERE id=:id")
45 | fun lastOpenedAt(id: String): LiveData
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/db/ent/Unipack.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.db.ent
2 |
3 | import androidx.room.Entity
4 | import androidx.room.PrimaryKey
5 | import java.util.Date
6 |
7 | @Entity
8 | class Unipack(
9 | @PrimaryKey
10 | var id: String,
11 | var bookmark: Boolean,
12 | var openCount: Long,
13 | var lastOpenedAt: Date?,
14 | // var deleted: Boolean,
15 | // var downloadedAt: Date,
16 | // var downloadFrom: String,
17 | var createdAt: Date,
18 | ) {
19 | override fun toString(): String {
20 | return "Unipack(id='$id', bookmark=$bookmark, openCount=$openCount, lastOpenedAt=$lastOpenedAt, createdAt=$createdAt)"
21 | }
22 |
23 | override fun equals(other: Any?): Boolean {
24 | if (this === other) return true
25 | if (javaClass != other?.javaClass) return false
26 |
27 | other as Unipack
28 |
29 | if (id != other.id) return false
30 | if (bookmark != other.bookmark) return false
31 | if (openCount != other.openCount) return false
32 | if (lastOpenedAt != other.lastOpenedAt) return false
33 | if (createdAt != other.createdAt) return false
34 |
35 | return true
36 | }
37 |
38 | override fun hashCode(): Int {
39 | var result = id.hashCode()
40 | result = 31 * result + bookmark.hashCode()
41 | result = 31 * result + openCount.hashCode()
42 | result = 31 * result + lastOpenedAt.hashCode()
43 | result = 31 * result + createdAt.hashCode()
44 | return result
45 | }
46 |
47 | companion object {
48 | fun create(id: String) = Unipack(id, false, 0, null, Date())
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
17 |
18 |
24 |
25 |
38 |
39 |
47 |
48 |
--------------------------------------------------------------------------------
/design/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-kapt'
4 |
5 | android {
6 | compileSdk 34
7 | defaultConfig {
8 | minSdkVersion 21
9 | targetSdkVersion 34
10 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
11 | vectorDrawables.useSupportLibrary true
12 | }
13 | buildTypes {
14 | release {
15 |
16 | minifyEnabled true
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | debug {
20 |
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
23 | }
24 | }
25 | buildFeatures {
26 | viewBinding true
27 | dataBinding true
28 | }
29 | compileOptions {
30 | sourceCompatibility JavaVersion.VERSION_1_8
31 | targetCompatibility JavaVersion.VERSION_1_8
32 | }
33 | kotlinOptions {
34 | jvmTarget = '1.8'
35 | }
36 | namespace 'com.kimjisub.design'
37 | }
38 |
39 | dependencies {
40 | implementation fileTree(dir: 'libs', include: ['*.jar'])
41 | testImplementation 'junit:junit:4.13.2'
42 |
43 | implementation 'androidx.appcompat:appcompat:1.6.1'
44 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
45 | implementation 'androidx.recyclerview:recyclerview:1.3.1'
46 | androidTestImplementation 'androidx.test:runner:1.5.2'
47 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
48 |
49 | kapt 'com.android.databinding:compiler:3.5.0'
50 |
51 | implementation 'com.polyak:icon-switch:1.0.0'
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_led_event_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
24 |
30 |
36 |
42 |
48 |
49 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_led_event_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
24 |
30 |
36 |
42 |
48 |
49 |
--------------------------------------------------------------------------------
/design/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | %1$td/%1$tm/%1$tY
4 |
5 |
6 | UniPacks Count
7 | UniPacks Size
8 | Play Count
9 | Theme
10 |
11 | - Title
12 | - Producer
13 | - Play Count
14 | - Last Opened Date
15 | - Download Date
16 |
17 |
18 |
19 | Pad Size
20 | Chain
21 | Sound files
22 | Led Events
23 | File Size
24 | Play Count
25 | Downloaded Date
26 | Last Played
27 | -
28 |
29 |
30 | Store UniPacks
31 | Downloaded UniPacks
32 |
33 |
34 | Download count
35 |
36 |
37 | Accept
38 | Couldn\'t read the folder.
39 | Couldn\'t read the file.
40 | MB
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/manager/ColorManager.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.manager
2 |
3 | import android.content.Context
4 | import androidx.core.content.ContextCompat
5 | import com.kimjisub.launchpad.R.color
6 |
7 | class ColorManager(val context: Context) {
8 | fun get(id: Int) = ContextCompat.getColor(context, id)
9 | private fun getLazy(id: Int) = lazy { get(id) }
10 |
11 | val background1 by getLazy(color.background1)
12 | val gray1 by getLazy(color.gray1)
13 | val background2 by getLazy(color.background2)
14 | val gray2 by getLazy(color.gray2)
15 | val white by getLazy(color.white)
16 |
17 |
18 | val title by getLazy(color.title)
19 | val subtitle by getLazy(color.subtitle)
20 |
21 |
22 | val checkbox by getLazy(color.checkbox)
23 | val trace_log by getLazy(color.trace_log)
24 | val option_window by getLazy(color.option_window)
25 | val option_window_checkbox by getLazy(color.option_window_checkbox)
26 | val option_window_btn by getLazy(color.option_window_btn)
27 | val option_window_btn_text by getLazy(color.option_window_btn_text)
28 |
29 |
30 | val skyblue by getLazy(color.skyblue)
31 | val blue by getLazy(color.blue)
32 | val green by getLazy(color.green)
33 | val orange by getLazy(color.orange)
34 | val red by getLazy(color.red)
35 | val pink by getLazy(color.pink)
36 |
37 |
38 | val border_icon_on_background by getLazy(color.border_icon_on_background)
39 | val popup_background by getLazy(color.popup_background)
40 |
41 |
42 | val app_orange by getLazy(color.app_orange)
43 | val app_blue by getLazy(color.app_blue)
44 | val app_blue_dark by getLazy(color.app_blue_dark)
45 | }
--------------------------------------------------------------------------------
/design/src/main/res/values/color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #161e2b
5 | #414F66
6 | #a6b4c9
7 | #808A99
8 | #f5f5f5
9 | #FFFFFF
10 |
11 |
12 | #FFFFFF
13 | #f5f5f5
14 | #9E9E9E
15 | #838383
16 | #535353
17 | #333
18 | #000
19 |
20 |
21 | #767d89
22 | #767d89
23 | #a1a6ae
24 |
25 |
26 | #a6b4c9
27 | #161e2b
28 | #FFFFFF
29 | #414F66
30 | #d6d8d7
31 | #0f0f0f
32 |
33 |
34 | #00bcda
35 | #4283e6
36 | #66bb6a
37 | #ffa726
38 | #ff6b4e
39 | #ffa5a5
40 |
41 |
42 | #ccc
43 | #3000
44 |
45 |
46 | #ff8f00
47 | #00b8d4
48 | #009db5
49 |
--------------------------------------------------------------------------------
/app/src/main/res/values/color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #161e2b
5 | #414F66
6 | #a6b4c9
7 | #808A99
8 | #f5f5f5
9 | #FFFFFF
10 |
11 |
12 | #FFFFFF
13 | #f5f5f5
14 | #9E9E9E
15 | #838383
16 | #535353
17 | #333
18 | #000
19 |
20 |
21 | #767d89
22 | #a1a6ae
23 |
24 |
25 | #a6b4c9
26 | #161e2b
27 | #FFFFFF
28 | #414F66
29 | #d6d8d7
30 | #0f0f0f
31 |
32 |
33 | #00bcda
34 | #4283e6
35 | #66bb6a
36 | #ffa726
37 | #ff6b4e
38 | #ffa5a5
39 |
40 |
41 | #ccc
42 | #3000
43 |
44 |
45 | #ff8f00
46 | #00b8d4
47 | #009db5
48 | #F5F5F5
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/activity/SettingsActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.activity
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.kimjisub.launchpad.databinding.ActivitySettingsBinding
6 | import com.kimjisub.launchpad.fragment.settings.HeaderFragment
7 | import com.kimjisub.launchpad.fragment.settings.HeaderFragment.Companion.Category
8 | import com.kimjisub.launchpad.fragment.settings.InfoFragment
9 | import com.kimjisub.launchpad.fragment.settings.StorageFragment
10 | import splitties.activities.start
11 |
12 | class SettingsActivity : AppCompatActivity() {
13 |
14 | lateinit var b: ActivitySettingsBinding
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | b = ActivitySettingsBinding.inflate(layoutInflater)
19 | setContentView(b.root)
20 |
21 | supportFragmentManager
22 | .beginTransaction()
23 | .replace(b.category.id, HeaderFragment {
24 | val fragment = when (it) {
25 | Category.INFO -> InfoFragment()
26 | Category.STORAGE -> StorageFragment()
27 | Category.THEME -> {
28 | start()
29 | // todo 이런식으로 fragment 띄우지 않는 경우에는
30 | // HeaderFragment 내부에서 select 값 바꾸지 않도록
31 | // ThemeFragment()
32 | null
33 | }
34 |
35 | else -> null
36 | }
37 |
38 | if (fragment != null) {
39 | supportFragmentManager.beginTransaction()
40 | .replace(b.settings.id, fragment)
41 | .commit()
42 | }
43 | })
44 | .commit()
45 | }
46 |
47 | override fun onSupportNavigateUp(): Boolean {
48 | if (supportFragmentManager.popBackStackImmediate()) {
49 | return true
50 | }
51 | return super.onSupportNavigateUp()
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/tool/Log.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.tool
2 |
3 | import android.util.Log
4 |
5 | object Log {
6 | private const val DEBUG = true
7 | fun log(msg: String) = printLog("com.kimjisub._log", msg)
8 | fun fbmsg(msg: String) = printLog("com.kimjisub._fbmsg", msg)
9 | fun test(msg: String) = printLog("com.kimjisub._test", msg)
10 | fun play(msg: String) = printLog("com.kimjisub._play", msg)
11 | fun download(msg: String) = printLog("com.kimjisub._download", msg)
12 | fun network(msg: String) = printLog("com.kimjisub._network", msg)
13 | fun activity(msg: String) = printLog("com.kimjisub._activity", msg)
14 | fun firebase(msg: String) = printLog("com.kimjisub._firebase", msg)
15 | fun midi(msg: String) = printLog("com.kimjisub._midi", msg)
16 | fun thread(msg: String) = printLog("com.kimjisub._thread", msg)
17 | fun midiDetail(msg: String) = printLog("com.kimjisub._mididetail", msg)
18 | fun driver(msg: String) = printLog("com.kimjisub._driver", msg)
19 | fun driverCycle(msg: String) = printLog("com.kimjisub._cycle", msg)
20 | fun err(msg: String) = printLog("com.kimjisub._err", msg)
21 |
22 | private fun printLog(tag: String, msg: String?) {
23 | val msg: String = msg ?: "(null)"
24 | var space = ""
25 | for (i in 0 until 30 - tag.length) space += " "
26 | val trace1 = trace(Thread.currentThread().stackTrace, 5)
27 | val trace2 = trace(Thread.currentThread().stackTrace, 4)
28 | val detailMsg = String.format("%s%-50s %-40s %-40s", space, msg, trace1, trace2)
29 | Log.e(tag, if (DEBUG) detailMsg else msg)
30 | }
31 |
32 | fun trace(e: Array?, level: Int): String? {
33 | if (e != null && e.size >= level)
34 | return "${e[level].methodName}(${e[level].fileName}:${e[level].lineNumber})"
35 | return null
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
30 |
31 |
36 |
37 |
45 |
46 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/design/src/main/java/com/kimjisub/design/layout/RadioButtonGroupTableLayout.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.layout
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.RadioButton
8 | import android.widget.TableLayout
9 | import android.widget.TableRow
10 |
11 |
12 | class RadioButtonGroupTableLayout
13 | @JvmOverloads constructor(
14 | context: Context,
15 | attrs: AttributeSet? = null,
16 | ) : TableLayout(context, attrs), View.OnClickListener {
17 | companion object {
18 | private const val TAG = "RadioButtonGroupTableLayout"
19 | }
20 |
21 | private var activeRadioButton: RadioButton? = null
22 |
23 | var onCheckedChangeListener: ((radioButton: RadioButton) -> Unit)? = null
24 |
25 | override fun onClick(v: View) {
26 | val rb = v as RadioButton
27 | if (activeRadioButton != null)
28 | activeRadioButton!!.isChecked = false
29 | rb.isChecked = true
30 | activeRadioButton = rb
31 |
32 | onCheckedChangeListener?.invoke(rb)
33 | }
34 |
35 | override fun addView(child: View, index: Int, params: ViewGroup.LayoutParams?) {
36 | super.addView(child, index, params)
37 | setChildrenOnClickListener(child as TableRow)
38 | }
39 |
40 | override fun addView(child: View, params: ViewGroup.LayoutParams?) {
41 | super.addView(child, params)
42 | setChildrenOnClickListener(child as TableRow)
43 | }
44 |
45 | private fun setChildrenOnClickListener(tr: TableRow) {
46 | val c: Int = tr.childCount
47 | for (i in 0 until c) {
48 | val v: View = tr.getChildAt(i)
49 | if (v is RadioButton) {
50 | v.setOnClickListener(this)
51 | }
52 | }
53 | }
54 |
55 | val checkedRadioButtonId: Int
56 | get() {
57 | return if (activeRadioButton != null)
58 | activeRadioButton!!.id
59 | else -1
60 | }
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/api/unipad/UniPadApi.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.api.unipad
2 |
3 | import com.kimjisub.launchpad.api.BaseApiService
4 | import com.kimjisub.launchpad.api.unipad.vo.UnishareVO
5 | import com.kimjisub.launchpad.tool.Log
6 | import okhttp3.OkHttpClient
7 | import okhttp3.logging.HttpLoggingInterceptor
8 | import okhttp3.logging.HttpLoggingInterceptor.Level
9 | import okhttp3.logging.HttpLoggingInterceptor.Logger
10 | import retrofit2.Call
11 | import retrofit2.Retrofit
12 | import retrofit2.Retrofit.Builder
13 | import retrofit2.converter.gson.GsonConverterFactory
14 | import retrofit2.http.Body
15 | import retrofit2.http.GET
16 | import retrofit2.http.POST
17 | import retrofit2.http.Path
18 |
19 | class UniPadApi : BaseApiService() {
20 |
21 | companion object {
22 | private const val URL = "https://api.unipad.io"
23 |
24 | val service: UniPadApiService by lazy {
25 | val httpLoggingInterceptor = HttpLoggingInterceptor(object : Logger {
26 | override fun log(message: String) {
27 | Log.network(message)
28 | }
29 | })
30 | httpLoggingInterceptor.level = Level.BODY
31 | val client: OkHttpClient = unsafeOkHttpClient
32 | .addInterceptor(httpLoggingInterceptor)
33 | .build()
34 | val retrofit: Retrofit = Builder()
35 | .baseUrl(URL)
36 | .addConverterFactory(GsonConverterFactory.create(gson))
37 | .client(client)
38 | .build()
39 | retrofit.create(UniPadApiService::class.java)
40 | }
41 |
42 | interface UniPadApiService {
43 |
44 | // unishare
45 |
46 | @GET("/unishare")
47 | fun getUnishares(): Call?>?
48 |
49 | @POST("/unishare")
50 | fun createUnishare(@Body item: UnishareVO?): Call?
51 |
52 | @GET("/unishare/{code}")
53 | fun getUnishare(@Path("code") code: String?): Call?
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/midi/driver/LaunchpadMK2.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.midi.driver
2 |
3 | class LaunchpadMK2 : DriverRef() {
4 | companion object {
5 | internal val circleCode = arrayOf(
6 | intArrayOf(11, -80, 104),
7 | intArrayOf(11, -80, 105),
8 | intArrayOf(11, -80, 106),
9 | intArrayOf(11, -80, 107),
10 | intArrayOf(11, -80, 108),
11 | intArrayOf(11, -80, 109),
12 | intArrayOf(11, -80, 110),
13 | intArrayOf(11, -80, 111),
14 | intArrayOf(9, -112, 89),
15 | intArrayOf(9, -112, 79),
16 | intArrayOf(9, -112, 69),
17 | intArrayOf(9, -112, 59),
18 | intArrayOf(9, -112, 49),
19 | intArrayOf(9, -112, 39),
20 | intArrayOf(9, -112, 29),
21 | intArrayOf(9, -112, 19)
22 | )
23 | }
24 |
25 | override fun getSignal(cmd: Int, sig: Int, note: Int, velocity: Int) {
26 | if (cmd == 9) {
27 | val x = 9 - note / 10
28 | val y = note % 10
29 | if (y in 1..8)
30 | onPadTouch(x - 1, y - 1, velocity != 0, velocity)
31 | else if (y == 9) {
32 | onChainTouch(x - 1, velocity != 0)
33 | onFunctionKeyTouch(x - 1 + 8, velocity != 0)
34 | }
35 | } else if (cmd == 11) {
36 | if (note in 104..111)
37 | onFunctionKeyTouch(note - 104, velocity != 0)
38 | }
39 | }
40 |
41 | override fun sendPadLed(x: Int, y: Int, velocity: Int) {
42 | sendSignal(9, -112, 10 * (8 - x) + y + 1, velocity)
43 | }
44 |
45 | override fun sendChainLed(c: Int, velocity: Int) {
46 | if (c in 0..7)
47 | sendFunctionkeyLed(c + 8, velocity)
48 | }
49 |
50 | override fun sendFunctionkeyLed(f: Int, velocity: Int) {
51 | if (f in 0..15)
52 | sendSignal(circleCode[f][0], circleCode[f][1], circleCode[f][2], velocity)
53 | }
54 |
55 | override fun sendClearLed() {
56 | for (i in 0..7)
57 | for (j in 0..7)
58 | sendPadLed(i, j, 0)
59 | for (i in 0..15) sendFunctionkeyLed(i, 0)
60 | }
61 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_importpack.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
15 |
24 |
25 |
30 |
31 |
35 |
36 |
44 |
45 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
30 |
31 |
38 |
39 |
42 |
43 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/activity/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.activity
2 |
3 | import android.Manifest.permission
4 | import android.os.Build
5 | import android.os.Bundle
6 | import android.os.Handler
7 | import android.os.Looper
8 | import com.gun0912.tedpermission.PermissionListener
9 | import com.gun0912.tedpermission.TedPermission
10 | import com.kimjisub.launchpad.BuildConfig
11 | import com.kimjisub.launchpad.R.string
12 | import com.kimjisub.launchpad.databinding.ActivitySplashBinding
13 | import splitties.activities.start
14 |
15 | class SplashActivity : BaseActivity() {
16 | private lateinit var b: ActivitySplashBinding
17 |
18 |
19 | // Timer
20 | internal var handler = Handler(Looper.getMainLooper())
21 | internal var runnable = Runnable {
22 | finish()
23 | start()
24 | }
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | super.onCreate(savedInstanceState)
28 | b = ActivitySplashBinding.inflate(layoutInflater)
29 | setContentView(b.root)
30 |
31 | b.version.text = BuildConfig.VERSION_NAME
32 |
33 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
34 | TedPermission.with(this)
35 | .setPermissionListener(object : PermissionListener {
36 | override fun onPermissionGranted() {
37 | handler.postDelayed(runnable, 2000)
38 | }
39 |
40 | override fun onPermissionDenied(deniedPermissions: List?) {
41 | handler.postDelayed(runnable, 2000)
42 | }
43 | })
44 | .setRationaleMessage(string.permissionRequire)
45 | .setDeniedMessage(string.permissionDenied)
46 | .setPermissions(
47 | permission.READ_EXTERNAL_STORAGE,
48 | permission.WRITE_EXTERNAL_STORAGE
49 | )
50 | .check()
51 | } else {
52 | handler.postDelayed(runnable, 2000)
53 | }
54 | }
55 |
56 | override fun onStop() {
57 | super.onStop()
58 | handler.removeCallbacks(runnable)
59 | finish()
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/fragment/settings/StorageFragment.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.fragment.settings
2 |
3 | import android.os.Bundle
4 | import androidx.preference.CheckBoxPreference
5 | import androidx.preference.PreferenceCategory
6 | import androidx.preference.PreferenceFragmentCompat
7 | import androidx.preference.children
8 | import com.kimjisub.launchpad.R
9 | import com.kimjisub.launchpad.manager.PreferenceManager
10 | import com.kimjisub.launchpad.manager.WorkspaceManager
11 | import org.koin.android.ext.android.inject
12 |
13 | class StorageFragment : PreferenceFragmentCompat() {
14 |
15 | val p: PreferenceManager by inject()
16 | val ws: WorkspaceManager by inject()
17 |
18 | private val storageListPreferenceCategory: PreferenceCategory by lazy { findPreference("storage_list")!! }
19 |
20 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
21 | setPreferencesFromResource(R.xml.preferences_storage, rootKey)
22 |
23 |
24 | initStorage()
25 | }
26 |
27 | private fun initStorage() {
28 | storageListPreferenceCategory.removeAll()
29 | ws.availableWorkspaces.forEach {
30 | val preference = CheckBoxPreference(context!!).apply {
31 | title = it.name
32 | summary = it.file.path
33 | isIconSpaceReserved = false
34 | setOnPreferenceChangeListener { _, newValue ->
35 | val list = p.storageActive.toMutableSet()
36 | if (newValue == true) {
37 | list.clear()
38 | list.add(it.file.path)
39 | } else if (list.size > 1)
40 | list.remove(it.file.path)
41 | p.storageActive = list
42 | ws.validateWorkspace()
43 | updateStorage()
44 |
45 | false
46 | }
47 | }
48 | storageListPreferenceCategory.addPreference(preference)
49 | }
50 | updateStorage()
51 | }
52 |
53 | private fun updateStorage() {
54 | storageListPreferenceCategory.children.forEach {
55 | (it as CheckBoxPreference).apply {
56 | isChecked = p.storageActive.contains(it.summary)
57 | }
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
17 |
23 |
29 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/design/src/main/java/com/kimjisub/design/view/ChainView.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.view
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.util.AttributeSet
6 | import android.view.LayoutInflater
7 | import android.widget.RelativeLayout
8 | import com.kimjisub.design.databinding.ViewChainBinding
9 |
10 | class ChainView
11 | @JvmOverloads constructor(
12 | context: Context,
13 | attrs: AttributeSet? = null,
14 | defStyleAttr: Int = 0,
15 | ) : RelativeLayout(context, attrs, defStyleAttr) {
16 | private val b: ViewChainBinding =
17 | ViewChainBinding.inflate(LayoutInflater.from(context), this, true)
18 |
19 |
20 | override fun setOnClickListener(listener: OnClickListener?) {
21 | b.touchSpace.setOnClickListener(listener)
22 | }
23 |
24 | override fun setOnTouchListener(listener: OnTouchListener) {
25 | b.touchSpace.setOnTouchListener(listener)
26 | }
27 | //========================================================================================= Background
28 |
29 |
30 | fun setBackgroundImageDrawable(drawable: Drawable?): ChainView {
31 | b.background.setImageDrawable(drawable)
32 | return this
33 | }
34 |
35 | //========================================================================================= LED
36 |
37 |
38 | fun setLedBackground(drawable: Drawable?): ChainView {
39 | b.led.background = drawable
40 | return this
41 | }
42 |
43 | fun setLedBackgroundColor(color: Int): ChainView {
44 | b.led.setBackgroundColor(color)
45 | return this
46 | }
47 |
48 | fun setLedVisibility(visibility: Int): ChainView {
49 | b.led.visibility = visibility
50 | return this
51 | }
52 |
53 | //========================================================================================= Phantom
54 |
55 |
56 | fun setPhantomImageDrawable(drawable: Drawable?): ChainView {
57 | b.phantom.setImageDrawable(drawable)
58 | return this
59 | }
60 |
61 | fun setPhantomRotation(rotation: Float): ChainView {
62 | b.phantom.rotation = rotation
63 | return this
64 | }
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/midi/driver/LaunchpadS.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.midi.driver
2 |
3 | import com.kimjisub.launchpad.manager.LaunchpadColor
4 |
5 | class LaunchpadS : DriverRef() {
6 | companion object {
7 | internal val circleCode = arrayOf(
8 | intArrayOf(11, -80, 104),
9 | intArrayOf(11, -80, 105),
10 | intArrayOf(11, -80, 106),
11 | intArrayOf(11, -80, 107),
12 | intArrayOf(11, -80, 108),
13 | intArrayOf(11, -80, 109),
14 | intArrayOf(11, -80, 110),
15 | intArrayOf(11, -80, 111),
16 | intArrayOf(9, -112, 8),
17 | intArrayOf(9, -112, 24),
18 | intArrayOf(9, -112, 40),
19 | intArrayOf(9, -112, 56),
20 | intArrayOf(9, -112, 72),
21 | intArrayOf(9, -112, 88),
22 | intArrayOf(9, -112, 104),
23 | intArrayOf(9, -112, 120)
24 | )
25 | }
26 |
27 | override fun getSignal(cmd: Int, sig: Int, note: Int, velocity: Int) {
28 | if (cmd == 9) {
29 | val x = note / 16 + 1
30 | val y = note % 16 + 1
31 | if (y in 1..8)
32 | onPadTouch(x - 1, y - 1, velocity != 0, velocity)
33 | else if (y == 9) {
34 | onChainTouch(x - 1, velocity != 0)
35 | onFunctionKeyTouch(x - 1 + 8, velocity != 0)
36 | }
37 | } else if (cmd == 11) {
38 | if (note in 104..111)
39 | onFunctionKeyTouch(note - 104, velocity != 0)
40 | }
41 | }
42 |
43 | override fun sendPadLed(x: Int, y: Int, velocity: Int) {
44 | sendSignal(9, -112, x * 16 + y, LaunchpadColor.SCode[velocity])
45 | }
46 |
47 | override fun sendChainLed(c: Int, velocity: Int) {
48 | if (c in 0..7)
49 | sendFunctionkeyLed(c + 8, velocity)
50 | }
51 |
52 | override fun sendFunctionkeyLed(f: Int, velocity: Int) {
53 | if (f in 0..15)
54 | sendSignal(
55 | circleCode[f][0].toByte(),
56 | circleCode[f][1].toByte(),
57 | circleCode[f][2].toByte(),
58 | LaunchpadColor.SCode[velocity].toByte()
59 | )
60 | }
61 |
62 | override fun sendClearLed() {
63 | for (i in 0..7)
64 | for (j in 0..7)
65 | sendPadLed(i, j, 0)
66 | for (i in 0..15)
67 | sendFunctionkeyLed(i, 0)
68 | }
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/manager/NotificationManager.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.manager
2 |
3 | import android.app.Notification
4 | import android.app.NotificationChannel
5 | import android.app.NotificationChannelGroup
6 | import android.app.NotificationManager
7 | import android.app.NotificationManager.IMPORTANCE_LOW
8 | import android.content.Context
9 | import android.graphics.Color
10 | import android.os.Build.VERSION
11 | import android.os.Build.VERSION_CODES
12 | import com.kimjisub.launchpad.R.string
13 |
14 | object NotificationManager {
15 | fun createChannel(context: Context) {
16 | if (VERSION.SDK_INT >= VERSION_CODES.O) {
17 | val manager = getManager(context)
18 |
19 | enumValues().forEach {
20 | val group = NotificationChannelGroup(it.name, context.getString(it.titleId))
21 | manager.createNotificationChannelGroup(group)
22 | }
23 |
24 | enumValues().forEach {
25 | val channel =
26 | NotificationChannel(it.name, context.getString(it.titleId), IMPORTANCE_LOW)
27 | channel.apply {
28 | description = context.getString(it.titleId) + " disc"
29 | group = it.group.name
30 | lightColor = it.colorId
31 | lockscreenVisibility = Notification.VISIBILITY_PUBLIC
32 | }
33 | manager.createNotificationChannel(channel)
34 | }
35 | }
36 | }
37 |
38 | fun getManager(context: Context): NotificationManager {
39 | return context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
40 | }
41 |
42 | fun deleteChannel(context: Context, channel: Channel) {
43 | if (VERSION.SDK_INT >= VERSION_CODES.O)
44 | getManager(context).deleteNotificationChannel(channel.name)
45 | }
46 |
47 | enum class Group(val titleId: Int) {
48 | General(string.general),
49 | Notice(string.notice)
50 | }
51 |
52 | enum class Channel(val titleId: Int, val group: Group, val colorId: Int) {
53 | Download(string.download, Group.General, Color.GREEN),
54 | Notice(string.notice, Group.Notice, Color.BLUE),
55 | NewPack(string.newUniPack, Group.Notice, Color.BLUE)
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/fragment/MainTotalPanelFragment.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.fragment
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.lifecycle.ViewModelProvider
9 | import com.kimjisub.launchpad.databinding.FragmentMainTotalPanelBinding
10 | import com.kimjisub.launchpad.tool.observeEvent
11 | import com.kimjisub.launchpad.viewmodel.MainTotalPanelViewModel
12 |
13 | class MainTotalPanelFragment : BaseFragment() {
14 | private var _b: FragmentMainTotalPanelBinding? = null
15 | private val b get() = _b!!
16 | private lateinit var vm: MainTotalPanelViewModel
17 |
18 | var sort: Pair? = null
19 |
20 | private var callbacks: Callbacks? = null
21 |
22 | interface Callbacks {
23 | fun onSortChangeListener(sort: Pair)
24 | }
25 |
26 | override fun onCreateView(
27 | inflater: LayoutInflater, container: ViewGroup?,
28 | savedInstanceState: Bundle?,
29 | ): View {
30 | vm = ViewModelProvider(
31 | this,
32 | MainTotalPanelViewModel.Factory(
33 | requireActivity().application,
34 | p,
35 | ws
36 | )
37 | )[MainTotalPanelViewModel::class.java]
38 | _b = FragmentMainTotalPanelBinding.inflate(inflater, container, false)
39 | b.apply {
40 | lifecycleOwner = this@MainTotalPanelFragment
41 | vm = this@MainTotalPanelFragment.vm
42 | }
43 |
44 | vm.eventSort.observeEvent(viewLifecycleOwner) {
45 | sort = it
46 | callbacks?.onSortChangeListener(it)
47 | }
48 |
49 | return b.root
50 | }
51 |
52 | fun update() {
53 | vm.update()
54 | }
55 |
56 | // Lifecycle
57 |
58 | override fun onAttach(context: Context) {
59 | super.onAttach(context)
60 | callbacks = context as Callbacks?
61 | }
62 |
63 | override fun onDetach() {
64 | super.onDetach()
65 | callbacks = null
66 | }
67 |
68 |
69 | override fun onDestroyView() {
70 | super.onDestroyView()
71 | _b = null
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_chain_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/ic_chain_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/app/proguard-retrofit2.pro:
--------------------------------------------------------------------------------
1 | # Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
2 | # EnclosingMethod is required to use InnerClasses.
3 | -keepattributes Signature, InnerClasses, EnclosingMethod
4 |
5 | # Retrofit does reflection on method and parameter annotations.
6 | -keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
7 |
8 | # Keep annotation default values (e.g., retrofit2.http.Field.encoded).
9 | -keepattributes AnnotationDefault
10 |
11 | # Retain service method parameters when optimizing.
12 | -keepclassmembers,allowshrinking,allowobfuscation interface * {
13 | @retrofit2.http.* ;
14 | }
15 |
16 | # Ignore annotation used for build tooling.
17 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
18 |
19 | # Ignore JSR 305 annotations for embedding nullability information.
20 | -dontwarn javax.annotation.**
21 |
22 | # Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
23 | -dontwarn kotlin.Unit
24 |
25 | # Top-level functions that can only be used by Kotlin.
26 | -dontwarn retrofit2.KotlinExtensions
27 | -dontwarn retrofit2.KotlinExtensions$*
28 |
29 | # With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
30 | # and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
31 | -if interface * { @retrofit2.http.* ; }
32 | -keep,allowobfuscation interface <1>
33 |
34 | # Keep inherited services.
35 | -if interface * { @retrofit2.http.* ; }
36 | -keep,allowobfuscation interface * extends <1>
37 |
38 | # With R8 full mode generic signatures are stripped for classes that are not
39 | # kept. Suspend functions are wrapped in continuations where the type argument
40 | # is used.
41 | -keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
42 |
43 | # R8 full mode strips generic signatures from return types if not kept.
44 | -if interface * { @retrofit2.http.* public *** *(...); }
45 | -keep,allowoptimization,allowshrinking,allowobfuscation class <3>
46 |
47 | # With R8 full mode generic signatures are stripped for classes that are not kept.
48 | -keep,allowobfuscation,allowshrinking class retrofit2.Response
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/activity/ThemeActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.activity
2 |
3 | import android.os.Bundle
4 | import com.azoft.carousellayoutmanager.CarouselLayoutManager
5 | import com.azoft.carousellayoutmanager.CarouselZoomPostLayoutListener
6 | import com.azoft.carousellayoutmanager.CenterScrollListener
7 | import com.kimjisub.launchpad.adapter.ThemeAdapter
8 | import com.kimjisub.launchpad.adapter.ThemeItem
9 | import com.kimjisub.launchpad.adapter.ThemeTool
10 | import com.kimjisub.launchpad.databinding.ActivityThemeBinding
11 | import com.kimjisub.launchpad.tool.Log
12 | import com.kimjisub.launchpad.tool.splitties.browse
13 |
14 | class ThemeActivity : BaseActivity() {
15 | private lateinit var b: ActivityThemeBinding
16 | val list: ArrayList by lazy { ThemeTool.getThemePackList(applicationContext) }
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | b = ActivityThemeBinding.inflate(layoutInflater)
21 | setContentView(b.root)
22 | }
23 |
24 | override fun onResume() {
25 | super.onResume()
26 | val manager = CarouselLayoutManager(CarouselLayoutManager.HORIZONTAL, false).apply {
27 | setPostLayoutListener(CarouselZoomPostLayoutListener())
28 | }
29 |
30 | b.list.apply {
31 | layoutManager = manager
32 | adapter = ThemeAdapter(list)
33 |
34 | setHasFixedSize(true)
35 | addOnScrollListener(CenterScrollListener())
36 | }
37 |
38 | manager.scrollToPosition(getSavedTheme())
39 |
40 | b.apply.setOnClickListener {
41 | selectTheme(manager.centerItemPosition)
42 | finish()
43 | }
44 | }
45 |
46 | private fun selectTheme(i: Int) {
47 | if (list.size != i)
48 | p.selectedTheme = list[i].package_name
49 | else
50 | browse("https://play.google.com/store/search?q=com.kimjisub.launchpad.theme.")
51 | }
52 |
53 | private fun getSavedTheme(): Int {
54 | var ret = 0
55 | val selectedThemePackageName: String = p.selectedTheme
56 | var i = 0
57 | for (themeItem in list) {
58 | Log.log(selectedThemePackageName + ", " + themeItem.package_name)
59 | if (themeItem.package_name == selectedThemePackageName) {
60 | ret = i
61 | break
62 | }
63 | i++
64 | }
65 | return ret
66 | }
67 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/manager/ChannelManager.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.manager
2 |
3 | class ChannelManager(x: Int, y: Int) {
4 | private var btn: Array>>
5 | private var cir: Array>
6 | private var btnIgnoreList: BooleanArray
7 | private var cirIgnoreList: BooleanArray
8 |
9 |
10 | enum class Channel(val priority: Int) {
11 | UI(0),
12 | UI_UNIPAD(1),
13 | GUIDE(2),
14 | PRESSED(3),
15 | CHAIN(3),
16 | LED(4);
17 | }
18 |
19 | data class Item(
20 | var channel: Channel,
21 | var color: Int,
22 | var code: Int,
23 | ) {
24 | override fun toString(): String {
25 | return "Item(channel=$channel, color=$color, code=$code)"
26 | }
27 | }
28 |
29 |
30 | init {
31 | btn = Array(x) { Array(y) { arrayOfNulls- (Channel.values().size) } }
32 | cir = Array(36) { arrayOfNulls
- (Channel.values().size) }
33 | btnIgnoreList = BooleanArray(Channel.values().size)
34 | cirIgnoreList = BooleanArray(Channel.values().size)
35 | }
36 |
37 |
38 | fun get(x: Int, y: Int): Item? {
39 | var ret: Item? = null
40 | if (x != -1) {
41 | for (i in Channel.values().indices) {
42 | if (btnIgnoreList[i])
43 | continue
44 | if (btn[x][y][i] != null) {
45 | ret = btn[x][y][i]
46 | break
47 | }
48 | }
49 | } else {
50 | for (i in Channel.values().indices) {
51 | if (cirIgnoreList[i])
52 | continue
53 | if (cir[y][i] != null) {
54 | ret = cir[y][i]
55 | break
56 | }
57 | }
58 | }
59 | return ret
60 | }
61 |
62 | fun add(x: Int, y: Int, channel: Channel, color: Int, code: Int) {
63 | var color = color
64 | if (color == -1)
65 | color = LaunchpadColor.ARGB[code].toInt()
66 | if (x != -1)
67 | btn[x][y][channel.priority] = Item(channel, color, code)
68 | else
69 | cir[y][channel.priority] = Item(channel, color, code)
70 | }
71 |
72 | fun remove(x: Int, y: Int, channel: Channel) {
73 | if (x != -1)
74 | btn[x][y][channel.priority] = null
75 | else
76 | cir[y][channel.priority] = null
77 | }
78 |
79 | fun setBtnIgnore(channel: Channel, ignore: Boolean) {
80 | btnIgnoreList[channel.priority] = ignore
81 | }
82 |
83 | fun setCirIgnore(channel: Channel, ignore: Boolean) {
84 | cirIgnoreList[channel.priority] = ignore
85 | }
86 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/network/Networks.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.network
2 |
3 | import com.google.firebase.database.ChildEventListener
4 | import com.google.firebase.database.DatabaseReference
5 | import com.google.firebase.database.FirebaseDatabase
6 | import com.google.firebase.database.ValueEventListener
7 | import java.io.BufferedReader
8 | import java.io.InputStreamReader
9 | import java.net.HttpURLConnection
10 | import java.net.URL
11 |
12 | object Networks {
13 | fun sendGet(str: String?): String {
14 | val html = StringBuilder()
15 | try {
16 | val url = URL(str)
17 | val conn = url.openConnection() as HttpURLConnection
18 | conn.connectTimeout = 10000
19 | conn.useCaches = false
20 | if (conn.responseCode == HttpURLConnection.HTTP_OK) {
21 | val br = BufferedReader(
22 | InputStreamReader(conn.inputStream)
23 | )
24 | while (true) {
25 | val line = br.readLine() ?: break
26 | html.append(line)
27 | html.append('\n')
28 | }
29 | br.close()
30 | }
31 | conn.disconnect()
32 | } catch (e: Exception) {
33 | e.printStackTrace()
34 | }
35 | return html.toString()
36 | }
37 |
38 | class FirebaseManager(key: String) {
39 | private var database: FirebaseDatabase = FirebaseDatabase.getInstance()
40 | private var myRef: DatabaseReference
41 | private var childEventListener: ChildEventListener? = null
42 | private var valueEventListener: ValueEventListener? = null
43 | fun setEventListener(childEventListener: ChildEventListener): FirebaseManager {
44 | this.childEventListener = childEventListener
45 | return this
46 | }
47 |
48 | fun setEventListener(valueEventListener: ValueEventListener): FirebaseManager {
49 | this.valueEventListener = valueEventListener
50 | return this
51 | }
52 |
53 | fun attachEventListener(bool: Boolean): FirebaseManager {
54 | if (childEventListener != null) if (bool) myRef.addChildEventListener(childEventListener!!) else myRef.removeEventListener(
55 | childEventListener!!
56 | )
57 | if (valueEventListener != null) if (bool) myRef.addValueEventListener(valueEventListener!!) else myRef.removeEventListener(
58 | valueEventListener!!
59 | )
60 | return this
61 | }
62 |
63 | init {
64 | myRef = database.getReference(key)
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_main_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
13 |
14 |
23 |
24 |
25 |
26 |
37 |
38 |
44 |
45 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/api/BaseApiService.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.api
2 |
3 |
4 | import android.annotation.SuppressLint
5 | import com.google.gson.*
6 | import okhttp3.OkHttpClient
7 | import java.lang.reflect.Type
8 | import java.security.SecureRandom
9 | import java.security.cert.X509Certificate
10 | import java.text.DateFormat
11 | import java.text.ParseException
12 | import java.text.SimpleDateFormat
13 | import java.util.*
14 | import javax.net.ssl.*
15 |
16 |
17 | open class BaseApiService {
18 |
19 | companion object {
20 |
21 | @SuppressLint("SimpleDateFormat")
22 | private val df: DateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
23 |
24 | val unsafeOkHttpClient: OkHttpClient.Builder
25 | get() {
26 | // Create a trust manager that does not validate certificate chains
27 |
28 |
29 | val trustAllCerts = arrayOf(
30 | object : X509TrustManager {
31 | override fun checkClientTrusted(
32 | chain: Array?,
33 | authType: String?,
34 | ) {
35 | }
36 |
37 | override fun checkServerTrusted(
38 | chain: Array?,
39 | authType: String?,
40 | ) {
41 | }
42 |
43 | override fun getAcceptedIssuers(): Array {
44 | return arrayOf()
45 | }
46 | }
47 | )
48 | val sslContext = SSLContext.getInstance("SSL")
49 | sslContext.init(null, trustAllCerts, SecureRandom())
50 | val sslSocketFactory = sslContext.socketFactory
51 | return OkHttpClient.Builder()
52 | .sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
53 | .hostnameVerifier(HostnameVerifier { _: String?, _: SSLSession? -> true })
54 |
55 | }
56 |
57 | val gson: Gson?
58 | get() {
59 | return GsonBuilder().registerTypeAdapter(
60 | Date::class.java,
61 | object : JsonDeserializer {
62 | @Throws(JsonParseException::class)
63 | override fun deserialize(
64 | json: JsonElement,
65 | typeOfT: Type?,
66 | context: JsonDeserializationContext?,
67 | ): Date? {
68 | return try {
69 | df.parse(json.asString)
70 | } catch (e: ParseException) {
71 | e.printStackTrace()
72 | null
73 | }
74 | }
75 | }).create()
76 | }
77 |
78 | }
79 |
80 |
81 | }
--------------------------------------------------------------------------------
/design/src/main/java/com/kimjisub/design/view/PadView.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.view
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.util.AttributeSet
6 | import android.view.LayoutInflater
7 | import android.widget.RelativeLayout
8 | import com.kimjisub.design.databinding.ViewPadBinding
9 |
10 | class PadView
11 | @JvmOverloads constructor(
12 | context: Context,
13 | attrs: AttributeSet? = null,
14 | defStyleAttr: Int = 0,
15 | ) : RelativeLayout(context, attrs, defStyleAttr) {
16 | private val b: ViewPadBinding =
17 | ViewPadBinding.inflate(LayoutInflater.from(context), this, true)
18 |
19 | override fun setOnClickListener(listener: OnClickListener?) {
20 | b.touchSpace.setOnClickListener(listener)
21 | }
22 |
23 | override fun setOnTouchListener(listener: OnTouchListener) {
24 | b.touchSpace.setOnTouchListener(listener)
25 | }
26 | //========================================================================================= Background
27 |
28 |
29 | fun setBackgroundImageDrawable(drawable: Drawable?): PadView {
30 | b.background.setImageDrawable(drawable)
31 | return this
32 | }
33 |
34 | //========================================================================================= LED
35 |
36 |
37 | fun setLedBackground(drawable: Drawable?): PadView {
38 | b.led.background = drawable
39 | return this
40 | }
41 |
42 | fun setLedBackgroundColor(color: Int): PadView {
43 | b.led.setBackgroundColor(color)
44 | return this
45 | }
46 |
47 | //========================================================================================= Phantom
48 |
49 |
50 | fun setPhantomImageDrawable(drawable: Drawable?): PadView {
51 | b.phantom.setImageDrawable(drawable)
52 | return this
53 | }
54 |
55 | fun setPhantomRotation(rotation: Float): PadView {
56 | b.phantom.rotation = rotation
57 | return this
58 | }
59 |
60 | //========================================================================================= TraceLog
61 |
62 |
63 | fun setTraceLogText(string: String?): PadView {
64 | b.traceLog.text = string
65 | return this
66 | }
67 |
68 | fun appendTraceLog(string: String?): PadView {
69 | b.traceLog.append(string)
70 | return this
71 | }
72 |
73 | fun setTraceLogTextColor(color: Int): PadView {
74 | b.traceLog.setTextColor(color)
75 | return this
76 | }
77 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/include_property_block.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
17 |
18 |
21 |
22 |
23 |
28 |
29 |
33 |
34 |
46 |
47 |
56 |
57 |
63 |
64 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/design/src/main/java/com/kimjisub/design/manage/SyncCheckBox.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.design.manage
2 |
3 | import android.widget.CheckBox
4 | import android.widget.CompoundButton
5 | import java.util.*
6 |
7 | class SyncCheckBox(vararg cbs: CheckBox) {
8 | private val checkBoxes: ArrayList = ArrayList()
9 |
10 | init {
11 | for (cb in cbs)
12 | addCheckBox(cb)
13 | }
14 |
15 | fun addCheckBox(vararg cbs: CheckBox) {
16 | for (cb in cbs) {
17 | cb.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean -> setChecked(b) }
18 | cb.setOnLongClickListener {
19 | onLongClick()
20 | false
21 | }
22 | checkBoxes.add(cb)
23 | }
24 | }
25 |
26 | // Checked Manage
27 |
28 | private var isChecked = false
29 | var isLocked: Boolean = false
30 | set(value) {
31 | field = value
32 | for (checkBox in checkBoxes) {
33 | checkBox.isEnabled = !field
34 | checkBox.alpha = if (!field) 1f else 0.3f
35 | }
36 | }
37 |
38 | fun isChecked() = isChecked
39 |
40 | fun toggleChecked() {
41 | if (!isLocked)
42 | forceToggleChecked()
43 | }
44 |
45 |
46 | fun setChecked(b: Boolean) {
47 | if (!isLocked)
48 | forceSetChecked(b)
49 | else
50 | fix()
51 | }
52 |
53 |
54 | fun forceToggleChecked() = forceSetChecked(!isChecked)
55 |
56 | fun forceSetChecked(b: Boolean) {
57 | isChecked = b
58 | fix()
59 | onCheckedChange(b)
60 | }
61 |
62 | fun fix() {
63 | for (checkBox in checkBoxes) {
64 | if (checkBox.isChecked != isChecked) {
65 | checkBox.setOnCheckedChangeListener(null)
66 | checkBox.isChecked = isChecked
67 | checkBox.setOnCheckedChangeListener { _: CompoundButton?, b: Boolean -> setChecked(b) }
68 | }
69 | }
70 | }
71 |
72 |
73 | // view
74 |
75 |
76 | fun setVisibility(visibility: Int) {
77 | for (checkBox in checkBoxes) checkBox.visibility = visibility
78 | }
79 |
80 |
81 | // listener
82 |
83 | var onCheckedChange: OnCheckedChange? = null
84 |
85 | var onLongClick: OnLongClick? = null
86 |
87 | interface OnCheckedChange {
88 | fun onCheckedChange(b: Boolean)
89 | }
90 |
91 | interface OnLongClick {
92 | fun onLongClick()
93 | }
94 |
95 | private fun onCheckedChange(bool: Boolean) {
96 | onCheckedChange?.onCheckedChange(bool)
97 | }
98 |
99 | private fun onLongClick() {
100 | onLongClick?.onLongClick()
101 | }
102 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/BaseApplication.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad
2 |
3 | import android.app.Application
4 | import android.os.Build
5 | import com.google.firebase.remoteconfig.FirebaseRemoteConfig
6 | import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings
7 | import com.kimjisub.launchpad.db.AppDatabase
8 | import com.kimjisub.launchpad.db.repository.UnipackRepository
9 | import com.kimjisub.launchpad.manager.NotificationManager
10 | import com.kimjisub.launchpad.manager.PreferenceManager
11 | import com.kimjisub.launchpad.manager.WorkspaceManager
12 | import com.orhanobut.logger.AndroidLogAdapter
13 | import com.orhanobut.logger.Logger
14 | import com.orhanobut.logger.PrettyFormatStrategy
15 | import org.koin.android.ext.koin.androidContext
16 | import org.koin.core.context.GlobalContext.startKoin
17 | import org.koin.dsl.module
18 |
19 | class BaseApplication : Application() {
20 | override fun onCreate() {
21 | super.onCreate()
22 |
23 | setupNotification()
24 | setupLogger()
25 | setupRemoteConfig()
26 |
27 | appOpenManager = AppOpenManager(this)
28 |
29 | startKoin {
30 | androidContext(applicationContext)
31 | modules(
32 | module {
33 | single {
34 | val db = AppDatabase.getInstance(applicationContext)!!
35 | UnipackRepository(db.unipackDAO())
36 | }
37 |
38 | single {
39 | PreferenceManager(applicationContext)
40 | }
41 |
42 | single {
43 | WorkspaceManager(applicationContext)
44 | }
45 | }
46 | )
47 | }
48 | }
49 |
50 | private fun setupNotification() {
51 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
52 | NotificationManager.createChannel(this)
53 | }
54 |
55 | private fun setupLogger() {
56 | val formatStrategy = PrettyFormatStrategy.newBuilder()
57 | .showThreadInfo(true)
58 | .methodCount(2)
59 | .methodOffset(5)
60 | .tag("com.kimjisub._")
61 | .build()
62 | Logger.addLogAdapter(AndroidLogAdapter())
63 | Logger.d("Logger Ready")
64 | }
65 |
66 | private fun setupRemoteConfig() {
67 | val remoteConfig = FirebaseRemoteConfig.getInstance()
68 |
69 | val configSettings = FirebaseRemoteConfigSettings.Builder().apply {
70 | if (BuildConfig.DEBUG)
71 | minimumFetchIntervalInSeconds = 60
72 | }.build()
73 |
74 | remoteConfig.setConfigSettingsAsync(configSettings)
75 | remoteConfig.fetchAndActivate()
76 | }
77 |
78 | companion object {
79 | private lateinit var appOpenManager: AppOpenManager
80 | }
81 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/fragment/MainPackPanelFragment.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.fragment
2 |
3 | import android.content.Context
4 | import android.content.DialogInterface
5 | import android.os.Bundle
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import androidx.appcompat.app.AlertDialog
10 | import androidx.lifecycle.ViewModelProvider
11 | import com.kimjisub.launchpad.R
12 | import com.kimjisub.launchpad.adapter.UniPackItem
13 | import com.kimjisub.launchpad.databinding.FragmentMainPackPanelBinding
14 | import com.kimjisub.launchpad.tool.observeEvent
15 | import com.kimjisub.launchpad.viewmodel.MainPackPanelViewModel
16 |
17 | class MainPackPanelFragment(private val unipackItem: UniPackItem) : BaseFragment() {
18 | private var _b: FragmentMainPackPanelBinding? = null
19 | private val b get() = _b!!
20 | private lateinit var vm: MainPackPanelViewModel
21 |
22 | private var callbacks: Callbacks? = null
23 |
24 | interface Callbacks {
25 | fun onDelete()
26 | }
27 |
28 | override fun onCreateView(
29 | inflater: LayoutInflater, container: ViewGroup?,
30 | savedInstanceState: Bundle?,
31 | ): View {
32 | vm = ViewModelProvider(
33 | this,
34 | MainPackPanelViewModel.Factory(
35 | requireActivity().application,
36 | unipackItem.unipack
37 | )
38 | )[MainPackPanelViewModel::class.java]
39 | _b = FragmentMainPackPanelBinding.inflate(inflater, container, false)
40 | b.apply {
41 | lifecycleOwner = this@MainPackPanelFragment
42 | vm = this@MainPackPanelFragment.vm
43 | }
44 |
45 | vm.eventDelete.observeEvent(viewLifecycleOwner) {
46 |
47 | AlertDialog.Builder(requireContext())
48 | .setTitle(R.string.warning)
49 | .setMessage(R.string.doYouWantToDeleteUniPack)
50 | .setPositiveButton(R.string.accept) { _: DialogInterface?, _: Int ->
51 | unipackItem.unipack.delete()
52 | callbacks?.onDelete()
53 | }.setNegativeButton(R.string.cancel, null)
54 | .show()
55 | }
56 |
57 | // 텍스트가 흘러갈 수 있도록 선택
58 | b.title.isSelected = true
59 | b.subtitle.isSelected = true
60 | b.path.isSelected = true
61 |
62 | return b.root
63 | }
64 |
65 | // Lifecycle
66 |
67 | override fun onAttach(context: Context) {
68 | super.onAttach(context)
69 | callbacks = context as Callbacks?
70 | }
71 |
72 | override fun onDetach() {
73 | super.onDetach()
74 | callbacks = null
75 | }
76 |
77 | override fun onDestroyView() {
78 | super.onDestroyView()
79 | _b = null
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UniPad Android Project
2 |
3 |
4 |
5 | ## Overview
6 |
7 | UniPad is a performance-based rhythm game that enables connection with a launchpad and allows users to create their own beatmaps using the unique "unipack" format, fostering creativity and sharing within the community.
8 |
9 | ## Features
10 |
11 | - Create custom beatmaps: Design your unique beatmaps and rhythms for various songs.
12 | - Share beatmaps: Share your creations with other users in the community.
13 | - Download community beatmaps: Access a diverse library of beatmaps created by others.
14 | - In-app song library: Utilize the Public Domain licensed music library provided by the app.
15 | - Frequent updates and bug fixes: Stay up-to-date with the latest features and improvements.
16 |
17 | ## Getting Started
18 |
19 | ### Prerequisites
20 |
21 | To run this project locally, you need to have the following software installed on your computer:
22 |
23 | 1. Android Studio (latest version)
24 | 2. Android SDK (latest version)
25 | 3. Git (for cloning the repository)
26 |
27 | ### Installation
28 |
29 | To set up this project on your local machine, follow these steps:
30 |
31 | 1. Clone the repository:
32 | git clone https://github.com/kimjisub/unipad-android.git
33 |
34 | 2. Open the project in Android Studio and let it sync the Gradle files.
35 |
36 | 3. Once the sync is done, build the project and run it on your Android device or emulator.
37 |
38 | ## Contributing
39 |
40 | We welcome contributions to this project! Please follow these steps if you would like to contribute:
41 |
42 | 1. Fork the repository.
43 | 2. Create a new branch with a descriptive name (e.g., `feat/new-functionality` or `fix/bug`).
44 | 3. Commit your changes to the new branch.
45 | 4. Push your changes to your forked repository.
46 | 5. Create a new pull request in the main repository.
47 |
48 | ## License
49 |
50 | This project is licensed under the [GNU Lesser General Public License v2.1](LICENSE.md) - see the `LICENSE.md` file for details.
51 |
52 | ## Acknowledgements
53 |
54 | - Thank you to the original UniPad app for inspiring this open-source project.
55 | - Thank you to all our contributors and users for making this project possible.
56 | - For questions or more information, feel free to reach out to 0226daniel@gmail.com.
57 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
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 %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="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 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/design/src/main/res/drawable/playbtn.xml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/midi/driver/LaunchpadX.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.midi.driver
2 |
3 | class LaunchpadX : DriverRef() {
4 | companion object {
5 | internal val circleCode = arrayOf(
6 | intArrayOf(27, -80, 91),
7 | intArrayOf(27, -80, 92),
8 | intArrayOf(27, -80, 93),
9 | intArrayOf(27, -80, 94),
10 | intArrayOf(27, -80, 95),
11 | intArrayOf(27, -80, 96),
12 | intArrayOf(27, -80, 97),
13 | intArrayOf(27, -80, 98),
14 | intArrayOf(27, -80, 89),
15 | intArrayOf(27, -80, 79),
16 | intArrayOf(27, -80, 69),
17 | intArrayOf(27, -80, 59),
18 | intArrayOf(27, -80, 49),
19 | intArrayOf(27, -80, 39),
20 | intArrayOf(27, -80, 29),
21 | intArrayOf(27, -80, 19),
22 | intArrayOf(27, -80, 8),
23 | intArrayOf(27, -80, 7),
24 | intArrayOf(27, -80, 6),
25 | intArrayOf(27, -80, 5),
26 | intArrayOf(27, -80, 4),
27 | intArrayOf(27, -80, 3),
28 | intArrayOf(27, -80, 2),
29 | intArrayOf(27, -80, 1),
30 | intArrayOf(27, -80, 10),
31 | intArrayOf(27, -80, 20),
32 | intArrayOf(27, -80, 30),
33 | intArrayOf(27, -80, 40),
34 | intArrayOf(27, -80, 50),
35 | intArrayOf(27, -80, 60),
36 | intArrayOf(27, -80, 70),
37 | intArrayOf(27, -80, 80)
38 | )
39 | }
40 |
41 | override fun getSignal(cmd: Int, sig: Int, note: Int, velocity: Int) {
42 | if (cmd == 25) {
43 | val x = 9 - note / 10
44 | val y = note % 10
45 | if (y in 1..8)
46 | onPadTouch(x - 1, y - 1, velocity != 0, velocity)
47 | } else if (cmd == 27 && sig == -80) {
48 | if (note in 91..98) {
49 | onFunctionKeyTouch(note - 91, velocity != 0)
50 | }
51 | if (note in 19..89 && note % 10 == 9) {
52 | val c = 9 - note / 10 - 1
53 | onChainTouch(c, velocity != 0)
54 | onFunctionKeyTouch(c + 8, velocity != 0)
55 | }
56 | if (note in 1..8) {
57 | onChainTouch(8 - note + 16 - 8, velocity != 0)
58 | onFunctionKeyTouch(8 - note + 16, velocity != 0)
59 | }
60 | if (note in 10..80 && note % 10 == 0) {
61 | onChainTouch(note / 10 - 1 + 24 - 8, velocity != 0)
62 | onFunctionKeyTouch(note / 10 - 1 + 24, velocity != 0)
63 | }
64 | } else {
65 | onUnknownReceived(cmd, sig, note, velocity)
66 | }
67 | }
68 |
69 | override fun sendPadLed(x: Int, y: Int, velocity: Int) {
70 | sendSignal(25, -112, 10 * (8 - x) + y + 1, velocity)
71 | }
72 |
73 | override fun sendChainLed(c: Int, velocity: Int) {
74 | if (c in 0..7)
75 | sendFunctionkeyLed(c + 8, velocity)
76 | }
77 |
78 | override fun sendFunctionkeyLed(f: Int, velocity: Int) {
79 | if (f in 0..31)
80 | sendSignal(
81 | circleCode[f][0].toByte(),
82 | circleCode[f][1].toByte(),
83 | circleCode[f][2].toByte(),
84 | velocity.toByte()
85 | )
86 | }
87 |
88 |
89 | override fun sendClearLed() {
90 | for (i in 0..7)
91 | for (j in 0..7)
92 | sendPadLed(i, j, 0)
93 | for (i in 0..31)
94 | sendFunctionkeyLed(i, 0)
95 | }
96 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/adapter/ThemeAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.adapter
2 |
3 | import android.content.Context
4 | import android.content.pm.ApplicationInfo
5 | import android.content.pm.PackageManager
6 | import android.content.res.Resources
7 | import android.graphics.drawable.Drawable
8 | import android.view.LayoutInflater
9 | import android.view.ViewGroup
10 | import androidx.recyclerview.widget.RecyclerView
11 | import com.kimjisub.launchpad.R.layout
12 | import com.kimjisub.launchpad.databinding.ItemThemeBinding
13 | import com.kimjisub.launchpad.manager.ThemeResources
14 |
15 | class ThemeItem(context: Context, val package_name: String) {
16 | val res: Resources = context.packageManager.getResourcesForApplication(package_name)
17 |
18 | val icon: Drawable =
19 | res.getDrawable(res.getIdentifier("$package_name:drawable/theme_ic", null, null))
20 | val name: String =
21 | res.getString(res.getIdentifier("$package_name:string/theme_name", null, null))
22 | val author: String =
23 | res.getString(res.getIdentifier("$package_name:string/theme_author", null, null))
24 | val description: String =
25 | res.getString(res.getIdentifier("$package_name:string/theme_description", null, null))
26 | val version: String? = context.packageManager.getPackageInfo(package_name, 0).versionName
27 |
28 | val resources: ThemeResources? = null
29 | }
30 |
31 | class ThemeHolder(val binding: ItemThemeBinding) : RecyclerView.ViewHolder(binding.root)
32 |
33 |
34 | class ThemeAdapter(val list: ArrayList) : RecyclerView.Adapter() {
35 |
36 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ThemeHolder {
37 | val view = LayoutInflater.from(parent.context)
38 | .inflate(layout.item_theme, parent, false)
39 |
40 | return ThemeHolder(ItemThemeBinding.bind(view))
41 | }
42 |
43 | override fun onBindViewHolder(holder: ThemeHolder, position: Int) {
44 | holder.apply {
45 | if (position < list.size)
46 | binding.data = list[position]
47 | else {
48 | val context = holder.binding.root.context
49 | binding.data = null
50 | }
51 | }
52 | }
53 |
54 | override fun getItemCount(): Int = list.size + 1
55 | }
56 |
57 | object ThemeTool {
58 | fun getThemePackList(context: Context): ArrayList {
59 | val ret = ArrayList()
60 | try {
61 | ret.add(ThemeItem(context, context.packageName))
62 | } catch (e: Exception) {
63 | e.printStackTrace()
64 | }
65 | val packages: List =
66 | context.packageManager.getInstalledApplications(PackageManager.GET_META_DATA)
67 | for (applicationInfo in packages) {
68 | val packageName: String = applicationInfo.packageName
69 | if (packageName.startsWith("com.kimjisub.launchpad.theme.")) {
70 | try {
71 | ret.add(ThemeItem(context, packageName))
72 | } catch (e: Exception) {
73 | e.printStackTrace()
74 | }
75 | }
76 | }
77 | return ret
78 | }
79 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_store.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
20 |
21 |
25 |
26 |
32 |
33 |
34 |
35 |
39 |
40 |
43 |
44 |
53 |
54 |
55 |
56 |
63 |
64 |
69 |
70 |
76 |
77 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kimjisub/launchpad/midi/driver/DriverRef.kt:
--------------------------------------------------------------------------------
1 | package com.kimjisub.launchpad.midi.driver
2 |
3 | import com.kimjisub.launchpad.tool.Log
4 |
5 | abstract class DriverRef {
6 |
7 | // OnCycleListener
8 |
9 | private var onCycleListener: OnCycleListener? = null
10 | fun setOnCycleListener(listener: OnCycleListener?): DriverRef {
11 | onCycleListener = listener
12 | return this
13 | }
14 |
15 | interface OnCycleListener {
16 | fun onConnected()
17 | fun onDisconnected()
18 | }
19 |
20 | ////
21 |
22 | fun onConnected() = onCycleListener?.onConnected()
23 |
24 | fun onDisconnected() = onCycleListener?.onDisconnected()
25 |
26 | // OnReceiveSignalListener
27 |
28 | private var onReceiveSignalListener: OnReceiveSignalListener? = null
29 | fun setOnGetSignalListener(listener: OnReceiveSignalListener?): DriverRef {
30 | onReceiveSignalListener = listener
31 | return this
32 | }
33 |
34 | interface OnReceiveSignalListener {
35 | fun onReceived(cmd: Int, sig: Int, note: Int, velocity: Int)
36 | fun onUnknownReceived(cmd: Int, sig: Int, note: Int, velocity: Int)
37 |
38 | fun onPadTouch(x: Int, y: Int, upDown: Boolean, velocity: Int)
39 | fun onChainTouch(c: Int, upDown: Boolean)
40 | fun onFunctionkeyTouch(f: Int, upDown: Boolean)
41 | }
42 |
43 | ////
44 |
45 |
46 | open fun getSignal(cmd: Int, sig: Int, note: Int, velocity: Int) {
47 | Log.midiDetail("onReceived($cmd, $sig, $note, $velocity)")
48 | onReceiveSignalListener?.onReceived(cmd, sig, note, velocity)
49 | }
50 |
51 | fun onPadTouch(x: Int, y: Int, upDown: Boolean, velocity: Int) {
52 | Log.midiDetail("onPadTouch($x, $y, $upDown, $velocity)")
53 | onReceiveSignalListener?.onPadTouch(x, y, upDown, velocity)
54 | }
55 |
56 | fun onChainTouch(c: Int, upDown: Boolean) {
57 | Log.midiDetail("onChainTouch($c, $upDown)")
58 | onReceiveSignalListener?.onChainTouch(c, upDown)
59 | }
60 |
61 | fun onFunctionKeyTouch(f: Int, upDown: Boolean) {
62 | Log.midiDetail("onFunctionKeyTouch($f, $upDown)")
63 | onReceiveSignalListener?.onFunctionkeyTouch(f, upDown)
64 | }
65 |
66 | fun onUnknownReceived(cmd: Int, sig: Int, note: Int, velocity: Int) {
67 | Log.midiDetail("onUnknownReceived($cmd, $sig, $note, $velocity)")
68 | onReceiveSignalListener?.onUnknownReceived(cmd, sig, note, velocity)
69 | }
70 |
71 | // OnSendSignalListener
72 |
73 | private var onSendSignalListener: OnSendSignalListener? = null
74 | fun setOnSendSignalListener(listener: OnSendSignalListener?): DriverRef {
75 | onSendSignalListener = listener
76 | return this
77 | }
78 |
79 | interface OnSendSignalListener {
80 | fun onSend(cmd: Byte, sig: Byte, note: Byte, velocity: Byte)
81 | }
82 |
83 | ////
84 |
85 | internal fun sendSignal(cmd: Byte, sig: Byte, note: Byte, velocity: Byte) {
86 | onSendSignalListener?.onSend(cmd, sig, note, velocity)
87 | }
88 |
89 | internal fun sendSignal(cmd: Int, sig: Int, note: Int, velocity: Int) {
90 | sendSignal(cmd.toByte(), sig.toByte(), note.toByte(), velocity.toByte())
91 | }
92 |
93 | abstract fun sendPadLed(x: Int, y: Int, velocity: Int)
94 | abstract fun sendChainLed(c: Int, velocity: Int)
95 | abstract fun sendFunctionkeyLed(f: Int, velocity: Int)
96 | abstract fun sendClearLed()
97 | }
--------------------------------------------------------------------------------