├── .idea ├── .name ├── codeStyles │ └── codeStyleConfig.xml ├── compiler.xml ├── vcs.xml ├── kotlinc.xml ├── dictionaries │ └── ashutyagi.xml ├── misc.xml ├── runConfigurations.xml ├── gradle.xml └── jarRepositories.xml ├── app ├── .gitignore ├── src │ ├── main │ │ ├── assets │ │ │ └── fonts │ │ │ │ ├── Lato.ttf │ │ │ │ ├── Lato-Bold.ttf │ │ │ │ ├── Lato-Black.ttf │ │ │ │ ├── Lato-Light.ttf │ │ │ │ └── Lato-Medium.ttf │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── logo.png │ │ │ │ ├── final_pallete.webp │ │ │ │ ├── ic_wallpaper.webp │ │ │ │ ├── bg_search.xml │ │ │ │ ├── list_divider.xml │ │ │ │ ├── bg_app_highlight.xml │ │ │ │ ├── bg_popup_app_info.xml │ │ │ │ ├── ripple_button.xml │ │ │ │ ├── fast_scroll_handle.xml │ │ │ │ ├── placeholder_big_image.xml │ │ │ │ ├── rounded_corner_button.xml │ │ │ │ ├── scroll_accent_drawable.xml │ │ │ │ ├── cb_selector.xml │ │ │ │ ├── ic_add_white.xml │ │ │ │ ├── divider_app_list.xml │ │ │ │ ├── ic_arrow_up_white.xml │ │ │ │ ├── bg_bottom_sheet_dialog_fragment.xml │ │ │ │ ├── ic_check_white.xml │ │ │ │ ├── ic_back_white.xml │ │ │ │ ├── ic_check_white_disabled.xml │ │ │ │ ├── ic_close_white.xml │ │ │ │ ├── ic_check_box_outline_white.xml │ │ │ │ ├── ripple_cell.xml │ │ │ │ ├── highlight.xml │ │ │ │ ├── ic_search_white.xml │ │ │ │ ├── state_pressed_ripple.xml │ │ │ │ ├── shadow.xml │ │ │ │ ├── ic_settings_white.xml │ │ │ │ ├── ic_info.xml │ │ │ │ ├── ic_checkbox_enabled.xml │ │ │ │ ├── ic_edit.xml │ │ │ │ ├── ic_refresh_white.xml │ │ │ │ └── ic_delete.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_settings.png │ │ │ │ └── ic_launcher_settings_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_settings.png │ │ │ │ └── ic_launcher_settings_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_settings.png │ │ │ │ └── ic_launcher_settings_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_settings.png │ │ │ │ └── ic_launcher_settings_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ ├── ic_launcher_settings.png │ │ │ │ └── ic_launcher_settings_round.png │ │ │ ├── anim │ │ │ │ ├── no_anim.xml │ │ │ │ ├── layout_animation_fall_down.xml │ │ │ │ ├── grid_layout_animation_from_bottom.xml │ │ │ │ ├── item_animation_from_bottom.xml │ │ │ │ ├── item_animation_fall_down.xml │ │ │ │ └── task_open_enter.xml │ │ │ ├── values │ │ │ │ ├── ic_launcher_settings_background.xml │ │ │ │ ├── integers.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── attrs.xml │ │ │ │ └── colors.xml │ │ │ ├── interpolator │ │ │ │ ├── decelerate_quart.xml │ │ │ │ └── decelerate_quint.xml │ │ │ ├── transition │ │ │ │ └── change_image_transform.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ ├── activity_screen_off.xml │ │ │ │ ├── cell_wallpaper_pager.xml │ │ │ │ ├── cell_wallpaper.xml │ │ │ │ ├── activity_wallpaper_pager.xml │ │ │ │ ├── activity_launcher.xml │ │ │ │ ├── cell_recent_app_section.xml │ │ │ │ ├── activity_launcher_settings.xml │ │ │ │ ├── cell_default_color.xml │ │ │ │ ├── cell_app_info_list.xml │ │ │ │ ├── cell_app_info.xml │ │ │ │ ├── activity_wallpaper_preview.xml │ │ │ │ ├── cell_setting.xml │ │ │ │ ├── activity_wallpaper_settings.xml │ │ │ │ └── cell_app_selector.xml │ │ │ ├── menu │ │ │ │ └── wallpaper.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ └── java │ │ │ └── com │ │ │ └── sasuke │ │ │ └── launcheroneplus │ │ │ ├── data │ │ │ ├── event │ │ │ │ └── NoInternetEvent.kt │ │ │ ├── model │ │ │ │ ├── Status.kt │ │ │ │ ├── Type.kt │ │ │ │ ├── Ancestry.kt │ │ │ │ ├── Category.kt │ │ │ │ ├── Tag.kt │ │ │ │ ├── CustomAppList.kt │ │ │ │ ├── DefaultColor.kt │ │ │ │ ├── DragData.kt │ │ │ │ ├── ProfileImage.kt │ │ │ │ ├── Wallpaper.kt │ │ │ │ ├── Links.kt │ │ │ │ ├── Urls.kt │ │ │ │ ├── AppInfo.kt │ │ │ │ ├── SettingPreference.kt │ │ │ │ ├── Source.kt │ │ │ │ ├── Error.kt │ │ │ │ ├── App.kt │ │ │ │ ├── CoverPhoto.kt │ │ │ │ ├── Setting.kt │ │ │ │ ├── Resource.kt │ │ │ │ ├── User.kt │ │ │ │ └── Result.kt │ │ │ ├── exception │ │ │ │ └── NoConnectivityException.kt │ │ │ ├── db │ │ │ │ ├── LauncherDB.kt │ │ │ │ ├── RoomRepository.kt │ │ │ │ └── dao │ │ │ │ │ └── AppsDao.kt │ │ │ └── network │ │ │ │ ├── UnsplashService.kt │ │ │ │ └── UnsplashRepository.kt │ │ │ ├── di │ │ │ ├── qualifiers │ │ │ │ ├── CacheInterceptor.kt │ │ │ │ ├── HeaderInterceptor.kt │ │ │ │ ├── NetworkInterceptor.kt │ │ │ │ ├── GridItemDecoration.kt │ │ │ │ ├── HiddenAppLayoutManager.kt │ │ │ │ ├── ListItemDecoration.kt │ │ │ │ ├── LoggingInterceptor.kt │ │ │ │ ├── StaleIfErrorInterceptor.kt │ │ │ │ ├── VisibleAppLayoutManager.kt │ │ │ │ └── ListDividerItemDecoration.kt │ │ │ ├── scope │ │ │ │ ├── LauncherAppScope.kt │ │ │ │ ├── PerActivityScope.kt │ │ │ │ └── PerFragmentScope.kt │ │ │ ├── mapkey │ │ │ │ └── ViewModelKey.kt │ │ │ ├── module │ │ │ │ ├── util │ │ │ │ │ ├── ViewModelFactoryModule.kt │ │ │ │ │ ├── SharedPreferenceModule.kt │ │ │ │ │ └── UtilsModule.kt │ │ │ │ ├── network │ │ │ │ │ ├── UnsplashRepositoryModule.kt │ │ │ │ │ └── UnsplashServiceModule.kt │ │ │ │ ├── library │ │ │ │ │ └── GlideModule.kt │ │ │ │ ├── application │ │ │ │ │ └── LauncherApplicationModule.kt │ │ │ │ ├── activity │ │ │ │ │ ├── AppDrawerActivityModule.kt │ │ │ │ │ ├── LauncherSettingsActivityModule.kt │ │ │ │ │ ├── WallpaperActivityModule.kt │ │ │ │ │ ├── WallpaperPagerActivityModule.kt │ │ │ │ │ ├── HiddenAppsActivityModule.kt │ │ │ │ │ ├── ActivityBindingModule.kt │ │ │ │ │ └── AppSelectionActivityModule.kt │ │ │ │ ├── local │ │ │ │ │ └── RoomRepositoryModule.kt │ │ │ │ └── fragment │ │ │ │ │ └── ColorPickerFragmentModule.kt │ │ │ └── component │ │ │ │ └── LauncherAppComponent.kt │ │ │ ├── util │ │ │ ├── GeneralUtils.kt │ │ │ ├── OnCustomEventListeners.kt │ │ │ ├── NetworkUtil.kt │ │ │ ├── StorageUtils.kt │ │ │ ├── SearchUtils.kt │ │ │ ├── Constants.kt │ │ │ ├── DaggerViewModelFactory.kt │ │ │ ├── DebouncingEditTextQueryTextListener.kt │ │ │ ├── DebouncingSearchViewQueryTextListener.kt │ │ │ ├── BitmapUtils.kt │ │ │ ├── ColorUtils.kt │ │ │ ├── PackageResolverUtils.kt │ │ │ ├── ApiCallback.kt │ │ │ ├── KeyboardTriggerBehavior.kt │ │ │ ├── SharedPreferencesSettingsLiveData.kt │ │ │ ├── Extensions.kt │ │ │ └── AppListUtil.kt │ │ │ ├── ui │ │ │ ├── widget │ │ │ │ ├── recyclerview_fastscroll │ │ │ │ │ ├── interfaces │ │ │ │ │ │ └── OnFastScrollStateChangeListener.java │ │ │ │ │ └── utils │ │ │ │ │ │ └── Utils.java │ │ │ │ └── GridRecyclerView.kt │ │ │ ├── base │ │ │ │ ├── MyItemKeyProvider.kt │ │ │ │ ├── MyItemDetailsLookup.kt │ │ │ │ ├── SpaceItemDecoration.kt │ │ │ │ ├── RoundedBottomSheetDialogFragment.kt │ │ │ │ ├── BaseViewHolder.kt │ │ │ │ ├── GridSpacingItemDecoration.kt │ │ │ │ └── MyDragShadowBuilder.kt │ │ │ ├── hidden_apps │ │ │ │ ├── HiddenAppsActivityViewModel.kt │ │ │ │ └── app_selector │ │ │ │ │ ├── VisibleAppSelectionViewHolder.kt │ │ │ │ │ ├── HiddenAppSelectionViewHolder.kt │ │ │ │ │ └── HiddenAppSelectionAdapter.kt │ │ │ ├── screen_off │ │ │ │ └── ScreenOffActivity.kt │ │ │ ├── color_picker │ │ │ │ ├── ColorPickerFragmentViewModel.kt │ │ │ │ ├── ColorViewHolder.kt │ │ │ │ └── ColorAdapter.kt │ │ │ ├── settings │ │ │ │ ├── LauncherSettingsActivityViewModel.kt │ │ │ │ ├── LauncherSettingViewHolder.kt │ │ │ │ ├── LauncherSettingAdapter.kt │ │ │ │ ├── set_as_default │ │ │ │ │ └── DefaultLauncherHandler.kt │ │ │ │ └── app_drawer │ │ │ │ │ └── AppDrawerActivityViewModel.kt │ │ │ ├── drag_drop │ │ │ │ ├── GridAppViewHolder.kt │ │ │ │ └── GridViewAdapter.kt │ │ │ ├── wallpaper │ │ │ │ └── list │ │ │ │ │ ├── grid │ │ │ │ │ ├── WallpaperViewHolder.kt │ │ │ │ │ ├── WallpaperAdapter.kt │ │ │ │ │ └── WallpaperActivityViewModel.kt │ │ │ │ │ └── pager │ │ │ │ │ ├── WallpaperPagerViewHolder.kt │ │ │ │ │ ├── WallpaperPagerAdapter.kt │ │ │ │ │ └── WallpaperPagerActivityViewModel.kt │ │ │ └── launcher │ │ │ │ └── recent_apps │ │ │ │ ├── RecentAppAdapter.kt │ │ │ │ └── RecentAppSectionViewHolder.kt │ │ │ └── receiver │ │ │ └── AppChangeReceiver.kt │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── sasuke │ │ │ └── launcheroneplus │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── sasuke │ │ └── launcheroneplus │ │ └── ExampleInstrumentedTest.kt └── google-services.json ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties └── gradlew.bat /.idea/.name: -------------------------------------------------------------------------------- 1 | Launcher OnePlus -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name='Launcher OnePlus' 2 | include ':app' 3 | -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Lato.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/assets/fonts/Lato.ttf -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/drawable/logo.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Lato-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/assets/fonts/Lato-Bold.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Lato-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/assets/fonts/Lato-Black.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Lato-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/assets/fonts/Lato-Light.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Lato-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/assets/fonts/Lato-Medium.ttf -------------------------------------------------------------------------------- /app/src/main/res/drawable/final_pallete.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/drawable/final_pallete.webp -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_wallpaper.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/drawable/ic_wallpaper.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/event/NoInternetEvent.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.event 2 | 3 | class NoInternetEvent { 4 | } -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/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/AshuTyagi16/Launcher-OnePlus/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/AshuTyagi16/Launcher-OnePlus/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/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_settings_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_settings_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_settings_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_settings_round.png -------------------------------------------------------------------------------- /app/src/main/res/anim/no_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_settings_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_settings_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_settings_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_settings_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_settings_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AshuTyagi16/Launcher-OnePlus/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_settings_round.png -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Status.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | enum class Status { 4 | SUCCESS, 5 | ERROR, 6 | LOADING 7 | } -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Type.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Type( 4 | val pretty_slug: String, 5 | val slug: String 6 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Ancestry.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Ancestry( 4 | val category: Category, 5 | val type: Type 6 | ) -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_settings_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #569DCF 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Category.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Category( 4 | val pretty_slug: String, 5 | val slug: String 6 | ) -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Tag.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Tag( 4 | val source: Source, 5 | val title: String, 6 | val type: String 7 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/CustomAppList.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class CustomAppList( 4 | val appList: List, 5 | var recentApp: List 6 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/DefaultColor.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class DefaultColor( 4 | val colorHex: Int, 5 | var isSelected: Boolean = false 6 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/DragData.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class DragData( 4 | val item: App, 5 | val width: Int, 6 | val height: Int 7 | ) -------------------------------------------------------------------------------- /app/src/main/res/interpolator/decelerate_quart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/interpolator/decelerate_quint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/dictionaries/ashutyagi.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | debouncing 5 | unsplash 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/ProfileImage.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class ProfileImage( 4 | val large: String, 5 | val medium: String, 6 | val small: String 7 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Wallpaper.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Wallpaper( 4 | val results: List, 5 | val total: Int, 6 | val total_pages: Int 7 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/CacheInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class CacheInterceptor { 7 | 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/HeaderInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class HeaderInterceptor { 7 | 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/NetworkInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class NetworkInterceptor { 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/GridItemDecoration.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class GridItemDecoration { 7 | 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/HiddenAppLayoutManager.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class HiddenAppLayoutManager { 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/ListItemDecoration.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class ListItemDecoration { 7 | 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/LoggingInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class LoggingInterceptor { 7 | 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/StaleIfErrorInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class StaleIfErrorInterceptor { 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/VisibleAppLayoutManager.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class VisibleAppLayoutManager { 7 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/scope/LauncherAppScope.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.scope 2 | 3 | import javax.inject.Scope 4 | 5 | @Scope 6 | @Retention(AnnotationRetention.RUNTIME) 7 | annotation class LauncherAppScope {} -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/scope/PerActivityScope.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.scope 2 | 3 | import javax.inject.Scope 4 | 5 | @Scope 6 | @Retention(AnnotationRetention.RUNTIME) 7 | annotation class PerActivityScope {} -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/scope/PerFragmentScope.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.scope 2 | 3 | import javax.inject.Scope 4 | 5 | @Scope 6 | @Retention(AnnotationRetention.RUNTIME) 7 | annotation class PerFragmentScope {} -------------------------------------------------------------------------------- /app/src/main/res/transition/change_image_transform.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/qualifiers/ListDividerItemDecoration.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.qualifiers 2 | 3 | import javax.inject.Qualifier 4 | 5 | @Qualifier 6 | annotation class ListDividerItemDecoration { 7 | 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Links.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Links( 4 | val download: String, 5 | val download_location: String, 6 | val html: String, 7 | val self: String 8 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Urls.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Urls( 4 | val full: String, 5 | val raw: String, 6 | val regular: String, 7 | val small: String, 8 | val thumb: String 9 | ) -------------------------------------------------------------------------------- /app/src/main/res/drawable/list_divider.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/AppInfo.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | import android.graphics.drawable.Drawable 4 | 5 | data class AppInfo( 6 | val icon: Drawable, 7 | val packageName: String, 8 | val label: String 9 | ) -------------------------------------------------------------------------------- /app/src/main/res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 200 4 | 300 5 | 400 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_app_highlight.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_popup_app_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Nov 16 19:17:55 IST 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-6.5-bin.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/layout_animation_fall_down.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/fast_scroll_handle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/placeholder_big_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rounded_corner_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/scroll_accent_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/cb_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_white.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/divider_app_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/SettingPreference.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class SettingPreference( 4 | var primaryColor: Int, 5 | var isFastScrollEnabled: Boolean = true, 6 | var drawerStyle: DrawerStyle = DrawerStyle.VERTICAL, 7 | var backgroundColor: Int, 8 | var backgroundColorAlpha: Int 9 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Source.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Source( 4 | val ancestry: Ancestry, 5 | val cover_photo: CoverPhoto, 6 | val description: String, 7 | val meta_description: String, 8 | val meta_title: String, 9 | val subtitle: String, 10 | val title: String 11 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Error.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | data class Error( 6 | 7 | @SerializedName("auth") 8 | val auth: Boolean = false, 9 | @SerializedName("message") 10 | val message: String = "Some Error Occurred" 11 | ) -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_up_white.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/exception/NoConnectivityException.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.exception 2 | 3 | import com.sasuke.launcheroneplus.util.Constants 4 | import java.io.IOException 5 | 6 | class NoConnectivityException : IOException() { 7 | 8 | override val message: String? 9 | get() = Constants.INTERNET_NOT_CONNECTED 10 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_screen_off.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/mapkey/ViewModelKey.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.mapkey 2 | 3 | import androidx.lifecycle.ViewModel 4 | import dagger.MapKey 5 | import kotlin.reflect.KClass 6 | 7 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) 8 | @MapKey 9 | annotation class ViewModelKey(val value: KClass) -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_bottom_sheet_dialog_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/grid_layout_animation_from_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/GeneralUtils.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.os.Build 4 | 5 | object GeneralUtils { 6 | 7 | val ATLEAST_MARSHMALLOW = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M 8 | 9 | val ATLEAST_LOLLIPOP_MR1 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 10 | 11 | val ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q 12 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_white.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_back_white.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_white_disabled.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/db/LauncherDB.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.db 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | import com.sasuke.launcheroneplus.data.db.dao.AppsDao 6 | import com.sasuke.launcheroneplus.data.model.App 7 | 8 | @Database(entities = [App::class], version = 1, exportSchema = false) 9 | abstract class LauncherDB : RoomDatabase() { 10 | abstract fun appsDao(): AppsDao 11 | } -------------------------------------------------------------------------------- /app/src/main/res/menu/wallpaper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close_white.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/test/java/com/sasuke/launcheroneplus/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/util/ViewModelFactoryModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.util 2 | 3 | import androidx.lifecycle.ViewModelProvider 4 | import com.sasuke.launcheroneplus.util.DaggerViewModelFactory 5 | import dagger.Binds 6 | import dagger.Module 7 | 8 | @Module 9 | abstract class ViewModelFactoryModule { 10 | @Binds 11 | abstract fun bindViewModelFactory(viewModelFactory: DaggerViewModelFactory): ViewModelProvider.Factory 12 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_box_outline_white.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple_cell.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/OnCustomEventListeners.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.view.View 4 | import com.sasuke.launcheroneplus.data.model.App 5 | 6 | interface OnCustomEventListeners { 7 | fun onItemClick(position: Int, parent: View, appInfo: App) 8 | fun onItemLongClick(position: Int, parent: View, appInfo: App) 9 | fun onDragStart(position: Int, parent: View, appInfo: App) 10 | fun onEventCancel(position: Int, appInfo: App) 11 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/highlight.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 26sp 6 | 22sp 7 | 20sp 8 | 18sp 9 | 16sp 10 | 14sp 11 | 12sp 12 | 10sp 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_white.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/item_animation_from_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/state_pressed_ripple.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/App.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | import android.os.Parcelable 4 | import androidx.room.ColumnInfo 5 | import androidx.room.Entity 6 | import androidx.room.PrimaryKey 7 | import kotlinx.android.parcel.Parcelize 8 | 9 | @Parcelize 10 | @Entity(tableName = "apps") 11 | data class App( 12 | @PrimaryKey(autoGenerate = true) val _id: Int = 0, 13 | val packageName: String, 14 | val label: String, 15 | var isSelected: Boolean = false, 16 | @ColumnInfo(name = "isHidden", index = true) 17 | var isHidden: Boolean = false 18 | ): Parcelable -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/widget/recyclerview_fastscroll/interfaces/OnFastScrollStateChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.widget.recyclerview_fastscroll.interfaces; 2 | 3 | public interface OnFastScrollStateChangeListener { 4 | 5 | /** 6 | * Called when fast scrolling begins 7 | */ 8 | void onFastScrollStart(); 9 | 10 | /** 11 | * Called when fast scroller is being dragged 12 | */ 13 | void onFastScrollDragged(String currentHeader); 14 | 15 | /** 16 | * Called when fast scrolling ends 17 | */ 18 | void onFastScrollStop(); 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/CoverPhoto.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class CoverPhoto( 4 | val alt_description: String, 5 | val categories: List, 6 | val color: String, 7 | val created_at: String, 8 | val current_user_collections: List, 9 | val description: String, 10 | val height: Int, 11 | val id: String, 12 | val liked_by_user: Boolean, 13 | val likes: Int, 14 | val links: Links, 15 | val promoted_at: String, 16 | val updated_at: String, 17 | val urls: Urls, 18 | val user: User, 19 | val width: Int 20 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Setting.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Setting( 4 | val icon: Int, 5 | val title: String, 6 | val description: String, 7 | val type: SettingsType, 8 | val shouldShow: Boolean = false 9 | ) 10 | 11 | enum class SettingsType { 12 | HOME_SCREEN, 13 | APP_DRAWER, 14 | FOLDERS, 15 | LOOK_FEEL, 16 | NIGHT_MODE, 17 | GESTURE_INPUT, 18 | NOTIFICATION_BADGE, 19 | DEFAULT_LAUNCHER, 20 | SAY_THANKS, 21 | ABOUT, 22 | CONTACT_SUPPORT 23 | } 24 | 25 | enum class DrawerStyle { 26 | VERTICAL, LIST 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Resource.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Resource(val status: Status, val data: T?, val message: String?) { 4 | companion object { 5 | fun success(data: T?): Resource { 6 | return Resource(Status.SUCCESS, data, null) 7 | } 8 | 9 | fun error(error: Error = Error(), data: T? = null): Resource { 10 | return Resource(Status.ERROR, data, error.message) 11 | } 12 | 13 | fun loading(data: T? = null): Resource { 14 | return Resource(Status.LOADING, data, null) 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/User.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class User( 4 | val accepted_tos: Boolean, 5 | val bio: String, 6 | val first_name: String, 7 | val id: String, 8 | val instagram_username: String, 9 | val last_name: String, 10 | val links: Links, 11 | val location: String, 12 | val name: String, 13 | val portfolio_url: String, 14 | val profile_image: ProfileImage, 15 | val total_collections: Int, 16 | val total_likes: Int, 17 | val total_photos: Int, 18 | val twitter_username: String, 19 | val updated_at: String, 20 | val username: String 21 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/model/Result.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.model 2 | 3 | data class Result( 4 | val alt_description: String, 5 | val categories: List, 6 | val color: String, 7 | val created_at: String, 8 | val current_user_collections: List, 9 | val description: String, 10 | val height: Int, 11 | val id: String, 12 | val liked_by_user: Boolean, 13 | val likes: Int, 14 | val links: Links, 15 | val promoted_at: String, 16 | val sponsorship: Any, 17 | val tags: List, 18 | val updated_at: String, 19 | val urls: Urls, 20 | val user: User, 21 | val width: Int 22 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/network/UnsplashRepositoryModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.network 2 | 3 | import com.sasuke.launcheroneplus.data.network.UnsplashRepository 4 | import com.sasuke.launcheroneplus.data.network.UnsplashService 5 | import com.sasuke.launcheroneplus.di.scope.LauncherAppScope 6 | import dagger.Module 7 | import dagger.Provides 8 | 9 | @Module(includes = [UnsplashServiceModule::class]) 10 | class UnsplashRepositoryModule { 11 | 12 | @Provides 13 | @LauncherAppScope 14 | fun newsAppRepository(unsplashService: UnsplashService): UnsplashRepository { 15 | return UnsplashRepository(unsplashService) 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/base/MyItemKeyProvider.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.base 2 | 3 | import androidx.recyclerview.selection.ItemKeyProvider 4 | import androidx.recyclerview.widget.RecyclerView 5 | 6 | class MyItemKeyProvider(private val recyclerView: RecyclerView) : 7 | ItemKeyProvider(SCOPE_MAPPED) { 8 | 9 | override fun getKey(position: Int): Long? { 10 | return recyclerView.adapter?.getItemId(position) 11 | } 12 | 13 | override fun getPosition(key: Long): Int { 14 | val viewHolder = recyclerView.findViewHolderForItemId(key) 15 | return viewHolder?.layoutPosition ?: RecyclerView.NO_POSITION 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/NetworkUtil.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util; 2 | 3 | import android.content.Context 4 | import android.net.ConnectivityManager 5 | import android.net.NetworkInfo 6 | 7 | class NetworkUtil(val context: Context) { 8 | 9 | private val connectivityManager: ConnectivityManager = context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 10 | private var networkInfo: NetworkInfo? = connectivityManager.activeNetworkInfo 11 | 12 | fun isOnline(): Boolean { 13 | networkInfo = connectivityManager.activeNetworkInfo 14 | networkInfo?.let { 15 | return it.isConnected 16 | } ?: run { return false } 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/base/MyItemDetailsLookup.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.base 2 | 3 | import android.view.MotionEvent 4 | import androidx.recyclerview.selection.ItemDetailsLookup 5 | import androidx.recyclerview.widget.RecyclerView 6 | 7 | class MyItemDetailsLookup(private val recyclerView: RecyclerView) : 8 | ItemDetailsLookup() { 9 | 10 | override fun getItemDetails(event: MotionEvent): ItemDetails? { 11 | val view = recyclerView.findChildViewUnder(event.x, event.y) 12 | if (view != null) { 13 | // return (recyclerView.getChildViewHolder(view) as AppViewHolder) 14 | // .getItemDetails() 15 | } 16 | return null 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/library/GlideModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.library 2 | 3 | import android.content.Context 4 | import com.bumptech.glide.Glide 5 | import com.bumptech.glide.RequestManager 6 | import com.bumptech.glide.load.DecodeFormat 7 | import com.bumptech.glide.request.RequestOptions 8 | import com.sasuke.launcheroneplus.di.scope.LauncherAppScope 9 | import dagger.Module 10 | import dagger.Provides 11 | 12 | @Module 13 | class GlideModule { 14 | 15 | @Provides 16 | @LauncherAppScope 17 | fun glide(context: Context): RequestManager { 18 | return Glide.with(context).setDefaultRequestOptions( 19 | RequestOptions().format(DecodeFormat.PREFER_RGB_565)) 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/StorageUtils.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import androidx.annotation.WorkerThread 6 | import java.io.File 7 | import java.io.FileOutputStream 8 | import java.io.IOException 9 | 10 | class StorageUtils(private val context: Context) { 11 | 12 | @WorkerThread 13 | fun saveBitmapToFile(bitmap: Bitmap, label: String) { 14 | try { 15 | FileOutputStream(File(context.getIconFolderPath(label))).use { out -> 16 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, out) 17 | } 18 | } catch (e: IOException) { 19 | e.printStackTrace() 20 | } 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/SearchUtils.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import androidx.annotation.WorkerThread 4 | 5 | object SearchUtils { 6 | 7 | @WorkerThread 8 | suspend fun matches( 9 | haystack: String, 10 | needle: String 11 | ): Boolean { 12 | val queryLength = needle.length 13 | val titleLength = haystack.length 14 | if (titleLength < queryLength || queryLength <= 0) { 15 | return false 16 | } 17 | var ni = 0 18 | var hi = 0 19 | while (hi < titleLength) { 20 | if (haystack[hi] == needle[ni]) { 21 | ni++ 22 | if (ni == queryLength) return true 23 | } 24 | hi++ 25 | } 26 | return false 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/sasuke/launcheroneplus/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.sasuke.launcheroneplus", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/res/anim/item_animation_fall_down.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/anim/task_open_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/cell_wallpaper_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/hidden_apps/HiddenAppsActivityViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.hidden_apps 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MediatorLiveData 5 | import androidx.lifecycle.ViewModel 6 | import com.sasuke.launcheroneplus.data.db.RoomRepository 7 | import com.sasuke.launcheroneplus.data.model.App 8 | import javax.inject.Inject 9 | 10 | class HiddenAppsActivityViewModel @Inject constructor(private val roomRepository: RoomRepository) : 11 | ViewModel() { 12 | 13 | private var _appList = MediatorLiveData>() 14 | val appList: LiveData> 15 | get() = _appList 16 | 17 | private lateinit var list: MutableList 18 | 19 | init { 20 | _appList.addSource(roomRepository.getOnlyHiddenApps()) { 21 | list = it 22 | _appList.postValue(it) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_white.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | object Constants { 4 | 5 | const val APP_LIST_SPAN_COUNT = 5 6 | 7 | val GRID_HORIZONTAL_SPACING = 5.dpToPx() 8 | val GRID_VERTICAL_SPACING = 20.dpToPx() 9 | 10 | val LIST_HORIZONTAL_SPACING = 5.dpToPx() 11 | val LIST_VERTICAL_SPACING = 10.dpToPx() 12 | 13 | const val EXTRA_API_VERSION_HEADER = "Accept-Version" 14 | const val EXTRA_API_VERSION = "v1" 15 | 16 | const val EXTRA_API_KEY = "S3wNzdfiMMhrwSDEJFIp-fPrzORJMXLBSyz_OIk5khE" 17 | 18 | const val PAGE_SIZE = 15 19 | 20 | const val ICON_FOLDER_NAME = "app_icon" 21 | 22 | const val RECENT_APPS = "RECENT_APPS" 23 | 24 | const val INTERNET_NOT_WORKING_MESSAGE = "Internet not working properly" 25 | const val INTERNET_NOT_CONNECTED = "Internet not connected" 26 | 27 | const val PREFERENCES = "SETTINGS_PREFERENCES" 28 | const val IS_PREFERENCES_SET = "IS_PREFERENCES_SET" 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/application/LauncherApplicationModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.application 2 | 3 | import com.sasuke.launcheroneplus.R 4 | import com.sasuke.launcheroneplus.di.scope.LauncherAppScope 5 | import dagger.Module 6 | import dagger.Provides 7 | import io.github.inflationx.calligraphy3.CalligraphyConfig 8 | import io.github.inflationx.calligraphy3.CalligraphyInterceptor 9 | import timber.log.Timber 10 | 11 | @Module 12 | object LauncherApplicationModule { 13 | 14 | @Provides 15 | @LauncherAppScope 16 | fun timberTree(): Timber.Tree { 17 | return Timber.DebugTree() 18 | } 19 | 20 | @Provides 21 | @LauncherAppScope 22 | fun calligraphyInterceptor(): CalligraphyInterceptor { 23 | return CalligraphyInterceptor( 24 | CalligraphyConfig.Builder() 25 | .setDefaultFontPath("fonts/Lato.ttf") 26 | .setFontAttrId(R.attr.fontPath) 27 | .build() 28 | ) 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/cell_wallpaper.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/screen_off/ScreenOffActivity.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.screen_off 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.view.Window 7 | import android.view.WindowManager 8 | import com.sasuke.launcheroneplus.R 9 | import com.sasuke.launcheroneplus.ui.base.BaseActivity 10 | 11 | class ScreenOffActivity : BaseActivity() { 12 | 13 | companion object { 14 | fun newIntent(context: Context) = Intent(context, ScreenOffActivity::class.java) 15 | } 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | setTimeout() 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.activity_screen_off) 21 | } 22 | 23 | private fun setTimeout() { 24 | requestWindowFeature(Window.FEATURE_NO_TITLE) 25 | this.window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN) 26 | val params = window.attributes 27 | params.screenBrightness = 0f 28 | window.attributes = params 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/network/UnsplashService.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.network 2 | 3 | import com.sasuke.launcheroneplus.data.model.Result 4 | import com.sasuke.launcheroneplus.data.model.Wallpaper 5 | import com.sasuke.launcheroneplus.util.Constants 6 | import retrofit2.Call 7 | import retrofit2.http.GET 8 | import retrofit2.http.Query 9 | 10 | interface UnsplashService { 11 | 12 | @GET("search/photos") 13 | fun getWallpapersForQuery( 14 | @Query("query") query: String = "Switzerland", 15 | @Query("client_id") client_id: String = Constants.EXTRA_API_KEY, 16 | @Query("orientation") orientation: String = "portrait", 17 | @Query("page") pageNo: Int = 1, 18 | @Query("per_page") per_page: Int = Constants.PAGE_SIZE 19 | ): Call 20 | 21 | @GET("photos") 22 | fun getPopular( 23 | @Query("order_by") order_by: String = "popular", 24 | @Query("client_id") client_id: String = Constants.EXTRA_API_KEY, 25 | @Query("page") pageNo: Int = 1, 26 | @Query("per_page") per_page: Int = 50 27 | ): Call> 28 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_checkbox_enabled.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/activity/AppDrawerActivityModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.activity 2 | 3 | import androidx.lifecycle.ViewModel 4 | import com.sasuke.launcheroneplus.di.mapkey.ViewModelKey 5 | import com.sasuke.launcheroneplus.di.module.fragment.ColorPickerFragmentModule 6 | import com.sasuke.launcheroneplus.di.scope.PerFragmentScope 7 | import com.sasuke.launcheroneplus.ui.color_picker.ColorPickerFragment 8 | import com.sasuke.launcheroneplus.ui.settings.app_drawer.AppDrawerActivityViewModel 9 | import dagger.Binds 10 | import dagger.Module 11 | import dagger.android.ContributesAndroidInjector 12 | import dagger.multibindings.IntoMap 13 | 14 | @Module 15 | abstract class AppDrawerActivityModule { 16 | 17 | @PerFragmentScope 18 | @ContributesAndroidInjector(modules = [ColorPickerFragmentModule::class]) 19 | internal abstract fun colorPickerFragment(): ColorPickerFragment 20 | 21 | @Binds 22 | @IntoMap 23 | @ViewModelKey(AppDrawerActivityViewModel::class) 24 | abstract fun bindAppDrawerActivityViewModel(appDrawerActivityViewModel: AppDrawerActivityViewModel): ViewModel 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/local/RoomRepositoryModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.local 2 | 3 | import android.content.Context 4 | import androidx.room.Room 5 | import com.sasuke.launcheroneplus.data.db.dao.AppsDao 6 | import com.sasuke.launcheroneplus.data.db.LauncherDB 7 | import com.sasuke.launcheroneplus.data.db.RoomRepository 8 | import com.sasuke.launcheroneplus.di.scope.LauncherAppScope 9 | import dagger.Module 10 | import dagger.Provides 11 | 12 | @Module 13 | class RoomRepositoryModule { 14 | 15 | @Provides 16 | @LauncherAppScope 17 | fun launcherDB(context: Context): LauncherDB { 18 | return Room.databaseBuilder( 19 | context, 20 | LauncherDB::class.java, "launcher_db" 21 | ).fallbackToDestructiveMigration().build() 22 | } 23 | 24 | @Provides 25 | @LauncherAppScope 26 | fun appDao(launcherDB: LauncherDB): AppsDao { 27 | return launcherDB.appsDao() 28 | } 29 | 30 | @Provides 31 | @LauncherAppScope 32 | fun roomRepository(appsDao: AppsDao): RoomRepository { 33 | return RoomRepository(appsDao) 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_wallpaper_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 22 | 23 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/DaggerViewModelFactory.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.ViewModelProvider 5 | import javax.inject.Inject 6 | import javax.inject.Provider 7 | 8 | @Suppress("UNCHECKED_CAST") 9 | class DaggerViewModelFactory @Inject constructor( 10 | private val creators: Map, @JvmSuppressWildcards Provider> 11 | ) : ViewModelProvider.Factory { 12 | @Suppress("UNCHECKED_CAST") 13 | override fun create(modelClass: Class): T { 14 | var creator: Provider? = creators[modelClass] 15 | if (creator == null) { 16 | for ((key, value) in creators) { 17 | if (modelClass.isAssignableFrom(key)) { 18 | creator = value 19 | break 20 | } 21 | } 22 | } 23 | if (creator == null) { 24 | throw IllegalArgumentException("Unknown model class: $modelClass") 25 | } 26 | try { 27 | return creator.get() as T 28 | } catch (e: Exception) { 29 | throw RuntimeException(e) 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /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 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/base/SpaceItemDecoration.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.base 2 | 3 | import android.graphics.Rect 4 | import android.view.View 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.sasuke.launcheroneplus.util.Constants 7 | 8 | class SpaceItemDecoration(private val horizontalSpace: Int, private val verticalSpace: Int) : 9 | RecyclerView.ItemDecoration() { 10 | 11 | companion object { 12 | private const val EDGE_SPACING_FACTOR = 1 13 | } 14 | 15 | override fun getItemOffsets( 16 | outRect: Rect, 17 | view: View, 18 | parent: RecyclerView, 19 | state: RecyclerView.State 20 | ) { 21 | outRect.left = horizontalSpace 22 | outRect.right = horizontalSpace 23 | 24 | if (parent.getChildLayoutPosition(view) == state.itemCount - 1) 25 | outRect.bottom = EDGE_SPACING_FACTOR * verticalSpace 26 | else 27 | outRect.bottom = verticalSpace 28 | 29 | if (parent.getChildLayoutPosition(view) >= 0 && parent.getChildLayoutPosition(view) < Constants.APP_LIST_SPAN_COUNT) 30 | outRect.top = EDGE_SPACING_FACTOR * verticalSpace 31 | else 32 | outRect.top = verticalSpace 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/cell_recent_app_section.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/util/SharedPreferenceModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.util 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import androidx.preference.PreferenceManager 6 | import com.google.gson.Gson 7 | import com.sasuke.launcheroneplus.di.scope.LauncherAppScope 8 | import com.sasuke.launcheroneplus.util.SharedPreferenceUtil 9 | import com.sasuke.launcheroneplus.util.SharedPreferencesSettingsLiveData 10 | import dagger.Module 11 | import dagger.Provides 12 | 13 | @Module 14 | object SharedPreferenceModule { 15 | 16 | @Provides 17 | @LauncherAppScope 18 | fun sharedPreferenceUtil(preferences: SharedPreferences, gson: Gson): SharedPreferenceUtil { 19 | return SharedPreferenceUtil(preferences, gson) 20 | } 21 | 22 | @Provides 23 | @LauncherAppScope 24 | fun preferences(context: Context): SharedPreferences { 25 | return PreferenceManager.getDefaultSharedPreferences(context) 26 | } 27 | 28 | @Provides 29 | @LauncherAppScope 30 | fun getSharedPreferencesUserLiveData( 31 | preferences: SharedPreferences, 32 | gson: Gson 33 | ): SharedPreferencesSettingsLiveData { 34 | return SharedPreferencesSettingsLiveData(preferences, gson) 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/color_picker/ColorPickerFragmentViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.color_picker 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import androidx.lifecycle.viewModelScope 7 | import com.google.gson.Gson 8 | import com.sasuke.launcheroneplus.data.model.DefaultColor 9 | import com.sasuke.launcheroneplus.util.ColorUtils 10 | import com.sasuke.launcheroneplus.util.Constants 11 | import com.sasuke.launcheroneplus.util.SharedPreferenceUtil 12 | import kotlinx.coroutines.Dispatchers 13 | import kotlinx.coroutines.launch 14 | import kotlinx.coroutines.withContext 15 | import javax.inject.Inject 16 | 17 | class ColorPickerFragmentViewModel @Inject constructor( 18 | private val colorUtils: ColorUtils 19 | ) : 20 | ViewModel() { 21 | 22 | private val _defaultColorsLiveData = MutableLiveData>() 23 | val defaultColorsLiveData: LiveData> 24 | get() = _defaultColorsLiveData 25 | 26 | fun getDefaultColorList() { 27 | viewModelScope.launch { 28 | withContext(Dispatchers.IO) { 29 | _defaultColorsLiveData.postValue(colorUtils.getDefaultColorHexList()) 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/settings/LauncherSettingsActivityViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.settings 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import androidx.lifecycle.viewModelScope 7 | import com.sasuke.launcheroneplus.data.model.Resource 8 | import com.sasuke.launcheroneplus.data.model.Setting 9 | import com.sasuke.launcheroneplus.util.SettingUtils 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.launch 12 | import kotlinx.coroutines.withContext 13 | import javax.inject.Inject 14 | 15 | class LauncherSettingsActivityViewModel @Inject constructor(private val settingUtils: SettingUtils) : 16 | ViewModel() { 17 | 18 | private val _settingsLiveData = MutableLiveData>>() 19 | val settingsLiveData: LiveData>> 20 | get() = _settingsLiveData 21 | 22 | fun getSettings() { 23 | _settingsLiveData.postValue(Resource.loading()) 24 | viewModelScope.launch { 25 | withContext(Dispatchers.IO) { 26 | val settings = settingUtils.getSettings().filter { 27 | it.shouldShow 28 | } 29 | _settingsLiveData.postValue(Resource.success(settings)) 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/base/RoundedBottomSheetDialogFragment.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.base 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.os.Bundle 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import androidx.annotation.LayoutRes 10 | import com.google.android.material.bottomsheet.BottomSheetDialog 11 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment 12 | import com.sasuke.launcheroneplus.R 13 | import dagger.android.support.AndroidSupportInjection 14 | 15 | abstract class RoundedBottomSheetDialogFragment : BottomSheetDialogFragment() { 16 | 17 | override fun onAttach(context: Context) { 18 | AndroidSupportInjection.inject(this) 19 | super.onAttach(context) 20 | } 21 | 22 | override fun getTheme(): Int = R.style.BottomSheetDialogTheme 23 | 24 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = 25 | BottomSheetDialog(requireContext(), theme) 26 | 27 | @LayoutRes 28 | abstract fun getLayoutResId(): Int 29 | 30 | override fun onCreateView( 31 | inflater: LayoutInflater, 32 | container: ViewGroup?, 33 | savedInstanceState: Bundle? 34 | ): View? { 35 | return inflater.inflate(getLayoutResId(), container, false) 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/network/UnsplashServiceModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.network 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.GsonBuilder 5 | import com.sasuke.launcheroneplus.data.network.UnsplashService 6 | import com.sasuke.launcheroneplus.di.scope.LauncherAppScope 7 | import dagger.Module 8 | import dagger.Provides 9 | import okhttp3.OkHttpClient 10 | import retrofit2.Retrofit 11 | import retrofit2.converter.gson.GsonConverterFactory 12 | 13 | @Module(includes = [NetworkModule::class]) 14 | class UnsplashServiceModule { 15 | 16 | companion object { 17 | private const val BASE_URL = "https://api.unsplash.com/" 18 | } 19 | 20 | @Provides 21 | @LauncherAppScope 22 | fun newsAppService(retrofit: Retrofit): UnsplashService { 23 | return retrofit.create(UnsplashService::class.java) 24 | } 25 | 26 | @Provides 27 | @LauncherAppScope 28 | fun retrofit(okHttpClient: OkHttpClient, gson: Gson): Retrofit { 29 | return Retrofit.Builder() 30 | .addConverterFactory(GsonConverterFactory.create(gson)) 31 | .client(okHttpClient) 32 | .baseUrl(BASE_URL) 33 | .build() 34 | } 35 | 36 | @Provides 37 | @LauncherAppScope 38 | fun gson(): Gson { 39 | return GsonBuilder().create() 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_launcher_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_edit.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/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 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/activity/LauncherSettingsActivityModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.activity 2 | 3 | import android.content.Context 4 | import androidx.lifecycle.ViewModel 5 | import androidx.recyclerview.widget.LinearLayoutManager 6 | import com.bumptech.glide.RequestManager 7 | import com.sasuke.launcheroneplus.di.mapkey.ViewModelKey 8 | import com.sasuke.launcheroneplus.di.scope.PerActivityScope 9 | import com.sasuke.launcheroneplus.ui.settings.LauncherSettingAdapter 10 | import com.sasuke.launcheroneplus.ui.settings.LauncherSettingsActivityViewModel 11 | import dagger.Binds 12 | import dagger.Module 13 | import dagger.Provides 14 | import dagger.multibindings.IntoMap 15 | 16 | @Module 17 | abstract class LauncherSettingsActivityModule { 18 | 19 | companion object { 20 | 21 | @Provides 22 | @PerActivityScope 23 | fun adapter(glide: RequestManager): LauncherSettingAdapter { 24 | return LauncherSettingAdapter(glide) 25 | } 26 | 27 | @Provides 28 | @PerActivityScope 29 | fun layoutManager(context: Context): LinearLayoutManager { 30 | return LinearLayoutManager(context) 31 | } 32 | } 33 | 34 | @Binds 35 | @IntoMap 36 | @ViewModelKey(LauncherSettingsActivityViewModel::class) 37 | abstract fun bindLauncherSettingsActivityViewModel(launcherSettingsActivityViewModel: LauncherSettingsActivityViewModel): ViewModel 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/db/RoomRepository.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.db 2 | 3 | import android.database.DatabaseUtils 4 | import android.util.Log 5 | import androidx.annotation.WorkerThread 6 | import androidx.lifecycle.LiveData 7 | import com.sasuke.launcheroneplus.data.db.dao.AppsDao 8 | import com.sasuke.launcheroneplus.data.model.App 9 | 10 | class RoomRepository(private val appsDao: AppsDao) { 11 | 12 | fun getApps(includeHidden: Boolean = false): LiveData> { 13 | if (includeHidden) 14 | return appsDao.getAllApps() 15 | else 16 | return appsDao.getVisibleApps(false) 17 | } 18 | 19 | fun getOnlyHiddenApps(): LiveData> { 20 | return appsDao.getOnlyHiddenApps(true) 21 | } 22 | 23 | fun isAppsInDB(): Int { 24 | return appsDao.isAppsInDB() 25 | } 26 | 27 | @WorkerThread 28 | suspend fun deleteAllApps() { 29 | return appsDao.deleteAllApps() 30 | } 31 | 32 | @WorkerThread 33 | suspend fun deleteApp(packageName: String) { 34 | return appsDao.deleteApp(packageName) 35 | } 36 | 37 | @WorkerThread 38 | suspend fun insert(app: App) { 39 | appsDao.insert(app) 40 | } 41 | 42 | @WorkerThread 43 | suspend fun hideApps(ids: IntArray) { 44 | appsDao.hideApps(ids, true) 45 | } 46 | 47 | @WorkerThread 48 | suspend fun unhideApps(ids: IntArray) { 49 | appsDao.unhideApps(ids, false) 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/db/dao/AppsDao.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.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.sasuke.launcheroneplus.data.model.App 9 | 10 | @Dao 11 | interface AppsDao { 12 | 13 | @Query("SELECT * from apps WHERE isHidden =:isHidden ORDER BY label COLLATE NOCASE ASC") 14 | fun getVisibleApps(isHidden: Boolean): LiveData> 15 | 16 | @Query("SELECT * from apps ORDER BY label COLLATE NOCASE ASC") 17 | fun getAllApps(): LiveData> 18 | 19 | @Query("SELECT * from apps WHERE isHidden =:isHidden ORDER BY label COLLATE NOCASE ASC") 20 | fun getOnlyHiddenApps(isHidden: Boolean): LiveData> 21 | 22 | @Query("SELECT COUNT(*) from apps") 23 | fun isAppsInDB(): Int 24 | 25 | @Insert(onConflict = OnConflictStrategy.REPLACE) 26 | suspend fun insert(app: App) 27 | 28 | @Query("UPDATE apps SET isHidden = :isHidden where _id IN(:ids)") 29 | suspend fun hideApps(ids: IntArray, isHidden: Boolean) 30 | 31 | @Query("UPDATE apps SET isHidden = :isHidden where _id IN(:ids)") 32 | suspend fun unhideApps(ids: IntArray, isHidden: Boolean) 33 | 34 | @Query("DELETE FROM apps") 35 | suspend fun deleteAllApps() 36 | 37 | @Query("DELETE FROM apps where packageName = :packageName") 38 | suspend fun deleteApp(packageName: String) 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/drag_drop/GridAppViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.drag_drop 2 | 3 | import android.view.View 4 | import androidx.recyclerview.widget.RecyclerView 5 | import com.bumptech.glide.RequestManager 6 | import com.sasuke.launcheroneplus.data.model.App 7 | import com.sasuke.launcheroneplus.util.Constants 8 | import com.sasuke.launcheroneplus.util.getIconFolderPath 9 | import kotlinx.android.synthetic.main.cell_app_info.view.* 10 | import java.io.File 11 | 12 | class GridAppViewHolder( 13 | itemView: View, 14 | private val glide: RequestManager 15 | ) : 16 | RecyclerView.ViewHolder(itemView) { 17 | 18 | private lateinit var onClickListeners: OnClickListeners 19 | 20 | fun setAppInfo(appInfo: App) { 21 | glide.load(File(itemView.context.getIconFolderPath(appInfo.label))) 22 | .into(itemView.ivAppIcon) 23 | itemView.tvAppLabel.text = appInfo.label 24 | 25 | itemView.setOnClickListener { 26 | if (::onClickListeners.isInitialized) 27 | onClickListeners.onItemClick(adapterPosition, itemView, appInfo) 28 | } 29 | 30 | itemView.setOnLongClickListener { 31 | return@setOnLongClickListener false 32 | } 33 | } 34 | 35 | interface OnClickListeners { 36 | fun onItemClick(position: Int, parent: View, appInfo: App) 37 | } 38 | 39 | fun setOnClickListeners(onClickListeners: OnClickListeners) { 40 | this.onClickListeners = onClickListeners 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/hidden_apps/app_selector/VisibleAppSelectionViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.hidden_apps.app_selector 2 | 3 | import android.view.View 4 | import androidx.recyclerview.widget.RecyclerView 5 | import com.bumptech.glide.RequestManager 6 | import com.sasuke.launcheroneplus.data.model.App 7 | import com.sasuke.launcheroneplus.util.Constants 8 | import com.sasuke.launcheroneplus.util.getIconFolderPath 9 | import kotlinx.android.synthetic.main.cell_app_selector.view.* 10 | import java.io.File 11 | 12 | class VisibleAppSelectionViewHolder(itemView: View, private val glide: RequestManager) : 13 | RecyclerView.ViewHolder(itemView) { 14 | 15 | private lateinit var onClickListeners: OnClickListeners 16 | 17 | fun setApp(appInfo: App) { 18 | glide.load(File(itemView.context.getIconFolderPath(appInfo.label))) 19 | .into(itemView.ivAppIcon) 20 | itemView.tvAppLabel.text = appInfo.label 21 | 22 | itemView.setOnClickListener { 23 | if (::onClickListeners.isInitialized) 24 | onClickListeners.onVisibleItemClick(adapterPosition, appInfo) 25 | } 26 | } 27 | 28 | fun toggle(checked: Boolean) { 29 | itemView.checkbox.isChecked = checked 30 | } 31 | 32 | interface OnClickListeners { 33 | fun onVisibleItemClick(position: Int, appInfo: App) 34 | } 35 | 36 | fun setOnClickListeners(onClickListeners: OnClickListeners) { 37 | this.onClickListeners = onClickListeners 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/cell_default_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/DebouncingEditTextQueryTextListener.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.text.Editable 4 | import android.text.TextWatcher 5 | import androidx.lifecycle.Lifecycle 6 | import androidx.lifecycle.LifecycleObserver 7 | import androidx.lifecycle.OnLifecycleEvent 8 | import kotlinx.coroutines.* 9 | 10 | class DebouncingEditTextQueryTextListener( 11 | lifecycle: Lifecycle, 12 | private val onDebouncingQueryTextChange: (CharSequence?) -> Unit 13 | ) : TextWatcher, LifecycleObserver { 14 | 15 | private var debouncePeriod: Long = 100 16 | 17 | private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.IO) 18 | 19 | private var searchJob: Job? = null 20 | 21 | init { 22 | lifecycle.addObserver(this) 23 | } 24 | 25 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 26 | private fun destroy() { 27 | searchJob?.cancel() 28 | } 29 | 30 | override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { 31 | 32 | } 33 | 34 | override fun onTextChanged(newText: CharSequence?, p1: Int, p2: Int, p3: Int) { 35 | searchJob?.cancel() 36 | searchJob = coroutineScope.launch { 37 | newText?.let { 38 | delay(debouncePeriod) 39 | withContext(Dispatchers.Main) { 40 | onDebouncingQueryTextChange(it.toString()) 41 | } 42 | } 43 | } 44 | } 45 | 46 | override fun afterTextChanged(p0: Editable?) { 47 | 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/DebouncingSearchViewQueryTextListener.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import androidx.lifecycle.Lifecycle 4 | import androidx.lifecycle.LifecycleObserver 5 | import androidx.lifecycle.OnLifecycleEvent 6 | import com.miguelcatalan.materialsearchview.MaterialSearchView 7 | import kotlinx.coroutines.* 8 | 9 | class DebouncingSearchViewQueryTextListener( 10 | lifecycle: Lifecycle, 11 | private val onDebouncingQueryTextChange: (String?) -> Unit 12 | ) : MaterialSearchView.OnQueryTextListener, LifecycleObserver { 13 | 14 | private var debouncePeriod: Long = 700 15 | 16 | private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Main) 17 | 18 | private var searchJob: Job? = null 19 | 20 | init { 21 | lifecycle.addObserver(this) 22 | } 23 | 24 | override fun onQueryTextSubmit(query: String?): Boolean { 25 | query?.let { 26 | onDebouncingQueryTextChange(it) 27 | return false 28 | } ?: run { 29 | return false 30 | } 31 | } 32 | 33 | override fun onQueryTextChange(newText: String?): Boolean { 34 | searchJob?.cancel() 35 | searchJob = coroutineScope.launch { 36 | newText?.let { 37 | delay(debouncePeriod) 38 | onDebouncingQueryTextChange(newText) 39 | } 40 | } 41 | return false 42 | } 43 | 44 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 45 | private fun destroy() { 46 | searchJob?.cancel() 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/fragment/ColorPickerFragmentModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.fragment 2 | 3 | import android.content.Context 4 | import androidx.lifecycle.ViewModel 5 | import androidx.recyclerview.widget.GridLayoutManager 6 | import com.sasuke.launcheroneplus.di.mapkey.ViewModelKey 7 | import com.sasuke.launcheroneplus.di.scope.PerFragmentScope 8 | import com.sasuke.launcheroneplus.ui.base.SpaceItemDecoration 9 | import com.sasuke.launcheroneplus.ui.color_picker.ColorAdapter 10 | import com.sasuke.launcheroneplus.ui.color_picker.ColorPickerFragmentViewModel 11 | import dagger.Binds 12 | import dagger.Module 13 | import dagger.Provides 14 | import dagger.multibindings.IntoMap 15 | 16 | @Module 17 | abstract class ColorPickerFragmentModule { 18 | 19 | companion object { 20 | 21 | @Provides 22 | @PerFragmentScope 23 | fun adapter(): ColorAdapter { 24 | return ColorAdapter() 25 | } 26 | 27 | @Provides 28 | @PerFragmentScope 29 | fun layoutManager(context: Context): GridLayoutManager { 30 | return GridLayoutManager(context, 4) 31 | } 32 | 33 | @Provides 34 | @PerFragmentScope 35 | fun itemDecoration(): SpaceItemDecoration { 36 | return SpaceItemDecoration(50, 30) 37 | } 38 | } 39 | 40 | @Binds 41 | @IntoMap 42 | @ViewModelKey(ColorPickerFragmentViewModel::class) 43 | abstract fun bindColorPickerFragmentViewModel(colorPickerFragmentViewModel: ColorPickerFragmentViewModel): ViewModel 44 | } -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "756468755900", 4 | "firebase_url": "https://launcheroneplus.firebaseio.com", 5 | "project_id": "launcheroneplus", 6 | "storage_bucket": "launcheroneplus.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:756468755900:android:6178da189526f9ba6ccfb9", 12 | "android_client_info": { 13 | "package_name": "com.sasuke.launcheroneplus" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "756468755900-mgj0ofvb17pduactdahj177l22mtqab5.apps.googleusercontent.com", 19 | "client_type": 1, 20 | "android_info": { 21 | "package_name": "com.sasuke.launcheroneplus", 22 | "certificate_hash": "9cfe111655147f35bf664b3f76f892d77cf26473" 23 | } 24 | }, 25 | { 26 | "client_id": "756468755900-fhr0gbeqpr8r5voju06tsn8m8d6pd7hu.apps.googleusercontent.com", 27 | "client_type": 3 28 | } 29 | ], 30 | "api_key": [ 31 | { 32 | "current_key": "AIzaSyAIRBkQ9EETrQSxmDSKRs265WutFApBPHc" 33 | } 34 | ], 35 | "services": { 36 | "appinvite_service": { 37 | "other_platform_oauth_client": [ 38 | { 39 | "client_id": "756468755900-fhr0gbeqpr8r5voju06tsn8m8d6pd7hu.apps.googleusercontent.com", 40 | "client_type": 3 41 | } 42 | ] 43 | } 44 | } 45 | } 46 | ], 47 | "configuration_version": "1" 48 | } -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/hidden_apps/app_selector/HiddenAppSelectionViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.hidden_apps.app_selector 2 | 3 | import android.view.View 4 | import androidx.recyclerview.widget.RecyclerView 5 | import com.bumptech.glide.RequestManager 6 | import com.sasuke.launcheroneplus.data.model.App 7 | import com.sasuke.launcheroneplus.util.Constants 8 | import com.sasuke.launcheroneplus.util.getIconFolderPath 9 | import kotlinx.android.synthetic.main.cell_app_selector.view.* 10 | import java.io.File 11 | 12 | class HiddenAppSelectionViewHolder(itemView: View, private val glide: RequestManager) : 13 | RecyclerView.ViewHolder(itemView) { 14 | 15 | private lateinit var onClickListeners: OnClickListeners 16 | 17 | fun setApp(appInfo: App) { 18 | glide.load(File(itemView.context.getIconFolderPath(appInfo.label))) 19 | .into(itemView.ivAppIcon) 20 | itemView.tvAppLabel.text = appInfo.label 21 | 22 | itemView.setOnClickListener { 23 | if (::onClickListeners.isInitialized) 24 | onClickListeners.onHiddenItemClick(adapterPosition, appInfo) 25 | } 26 | 27 | if (appInfo.isHidden) 28 | itemView.checkbox.isChecked = true 29 | } 30 | 31 | fun toggle(checked: Boolean) { 32 | itemView.checkbox.isChecked = checked 33 | } 34 | 35 | interface OnClickListeners { 36 | fun onHiddenItemClick(position: Int, appInfo: App) 37 | } 38 | 39 | fun setOnClickListeners(onClickListeners: OnClickListeners) { 40 | this.onClickListeners = onClickListeners 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh_white.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/cell_app_info_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 20 | 21 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/BitmapUtils.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.graphics.Bitmap 4 | import android.graphics.BitmapFactory 5 | import android.graphics.Canvas 6 | import android.graphics.drawable.BitmapDrawable 7 | import android.graphics.drawable.Drawable 8 | import androidx.annotation.WorkerThread 9 | 10 | class BitmapUtils { 11 | 12 | @WorkerThread 13 | fun drawableToBitmap(drawable: Drawable): Bitmap? { 14 | var bitmap: Bitmap? = null 15 | if (drawable is BitmapDrawable) { 16 | if (drawable.bitmap != null) { 17 | return drawable.bitmap 18 | } 19 | } 20 | bitmap = if (drawable.intrinsicWidth <= 0 || drawable.intrinsicHeight <= 0) { 21 | Bitmap.createBitmap( 22 | 1, 23 | 1, 24 | Bitmap.Config.ARGB_8888 25 | ) // Single color bitmap will be created of 1x1 pixel 26 | } else { 27 | Bitmap.createBitmap( 28 | drawable.intrinsicWidth/2, 29 | drawable.intrinsicHeight/2, 30 | Bitmap.Config.ARGB_8888 31 | ) 32 | } 33 | val canvas = Canvas(bitmap) 34 | drawable.setBounds(0, 0, canvas.width, canvas.height) 35 | drawable.draw(canvas) 36 | return bitmap 37 | } 38 | 39 | @WorkerThread 40 | suspend fun getBitmapFromPath(path: String): Bitmap? { 41 | val options = BitmapFactory.Options() 42 | options.inPreferredConfig = Bitmap.Config.ARGB_8888 43 | return BitmapFactory.decodeFile(path, options) 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/util/UtilsModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.util 2 | 3 | import android.content.Context 4 | import com.sasuke.launcheroneplus.data.db.RoomRepository 5 | import com.sasuke.launcheroneplus.di.module.local.RoomRepositoryModule 6 | import com.sasuke.launcheroneplus.di.scope.LauncherAppScope 7 | import com.sasuke.launcheroneplus.util.* 8 | import dagger.Module 9 | import dagger.Provides 10 | 11 | @Module(includes = [RoomRepositoryModule::class]) 12 | class UtilsModule { 13 | 14 | @Provides 15 | @LauncherAppScope 16 | fun storageUtils(context: Context): StorageUtils { 17 | return StorageUtils(context) 18 | } 19 | 20 | @Provides 21 | @LauncherAppScope 22 | fun bitmapUtils(): BitmapUtils { 23 | return BitmapUtils() 24 | } 25 | 26 | @Provides 27 | @LauncherAppScope() 28 | fun appListUtils( 29 | roomRepository: RoomRepository, 30 | bitmapUtils: BitmapUtils, 31 | storageUtils: StorageUtils, 32 | context: Context 33 | ): AppListUtil { 34 | return AppListUtil(roomRepository, bitmapUtils, storageUtils, context.packageManager, context) 35 | } 36 | 37 | @Provides 38 | @LauncherAppScope 39 | fun networkUtil(context: Context): NetworkUtil { 40 | return NetworkUtil(context) 41 | } 42 | 43 | @Provides 44 | @LauncherAppScope 45 | fun settingUtils(context: Context): SettingUtils { 46 | return SettingUtils(context) 47 | } 48 | 49 | @Provides 50 | @LauncherAppScope 51 | fun colorUtils(context: Context): ColorUtils { 52 | return ColorUtils(context) 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/base/BaseViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.base 2 | 3 | import android.view.View 4 | import androidx.dynamicanimation.animation.SpringAnimation 5 | import androidx.dynamicanimation.animation.SpringForce 6 | import androidx.recyclerview.widget.RecyclerView 7 | 8 | open class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 9 | var currentVelocity = 0f 10 | 11 | /** 12 | * A [SpringAnimation] for this RecyclerView item. This animation rotates the view with a bouncy 13 | * spring configuration, resulting in the oscillation effect. 14 | * 15 | * The animation is started in [Recyclerview.onScrollListener]. 16 | */ 17 | val rotation: SpringAnimation = SpringAnimation(itemView, SpringAnimation.ROTATION) 18 | .setSpring( 19 | SpringForce() 20 | .setFinalPosition(0f) 21 | .setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY) 22 | .setStiffness(SpringForce.STIFFNESS_LOW) 23 | ) 24 | .addUpdateListener { _, _, velocity -> 25 | currentVelocity = velocity 26 | } 27 | 28 | /** 29 | * A [SpringAnimation] for this RecyclerView item. This animation is used to bring the item back 30 | * after the over-scroll effect. 31 | */ 32 | val translationY: SpringAnimation = SpringAnimation(itemView, SpringAnimation.TRANSLATION_Y) 33 | .setSpring( 34 | SpringForce() 35 | .setFinalPosition(0f) 36 | .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY) 37 | .setStiffness(SpringForce.STIFFNESS_LOW) 38 | ) 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/color_picker/ColorViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.color_picker 2 | 3 | import android.view.View 4 | import androidx.appcompat.content.res.AppCompatResources 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.sasuke.launcheroneplus.R 7 | import com.sasuke.launcheroneplus.data.model.DefaultColor 8 | import com.sasuke.launcheroneplus.util.hide 9 | import com.sasuke.launcheroneplus.util.show 10 | import com.sasuke.launcheroneplus.util.updateTint 11 | import kotlinx.android.synthetic.main.cell_default_color.view.* 12 | 13 | class ColorViewHolder(itemView: View) : 14 | RecyclerView.ViewHolder(itemView) { 15 | 16 | private lateinit var onClickListeners: OnClickListeners 17 | 18 | fun setColor(color: DefaultColor) { 19 | AppCompatResources.getDrawable(itemView.context, R.drawable.scroll_accent_drawable) 20 | ?.let { drawable -> 21 | drawable.updateTint(color.colorHex) 22 | itemView.ivColor.background = drawable 23 | } 24 | 25 | itemView.setOnClickListener { 26 | if (::onClickListeners.isInitialized) 27 | onClickListeners.onItemClick(adapterPosition, color.colorHex) 28 | } 29 | } 30 | 31 | fun toggle(flag: Boolean) { 32 | if (flag) 33 | itemView.ivSelected.show() 34 | else 35 | itemView.ivSelected.hide() 36 | } 37 | 38 | interface OnClickListeners { 39 | fun onItemClick(position: Int, color: Int) 40 | } 41 | 42 | fun setOnClickListeners(onClickListeners: OnClickListeners) { 43 | this.onClickListeners = onClickListeners 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/base/GridSpacingItemDecoration.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.base 2 | 3 | import android.graphics.Rect 4 | import android.view.View 5 | import androidx.recyclerview.widget.RecyclerView 6 | import androidx.recyclerview.widget.RecyclerView.ItemDecoration 7 | 8 | class GridSpacingItemDecoration( 9 | private val spanCount: Int, 10 | private val spacing: Int, 11 | private val includeEdge: Boolean 12 | ) : ItemDecoration() { 13 | override fun getItemOffsets( 14 | outRect: Rect, 15 | view: View, 16 | parent: RecyclerView, 17 | state: RecyclerView.State 18 | ) { 19 | val position = parent.getChildAdapterPosition(view) // item position 20 | val column = position % spanCount // item column 21 | if (includeEdge) { 22 | outRect.left = 23 | spacing - column * spacing / spanCount // spacing - column * ((1f / spanCount) * spacing) 24 | outRect.right = 25 | (column + 1) * spacing / spanCount // (column + 1) * ((1f / spanCount) * spacing) 26 | if (position < spanCount) { // top edge 27 | outRect.top = spacing 28 | } 29 | outRect.bottom = spacing // item bottom 30 | } else { 31 | outRect.left = column * spacing / spanCount // column * ((1f / spanCount) * spacing) 32 | outRect.right = 33 | spacing - (column + 1) * spacing / spanCount // spacing - (column + 1) * ((1f / spanCount) * spacing) 34 | if (position >= spanCount) { 35 | outRect.top = spacing // item top 36 | } 37 | } 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/activity/WallpaperActivityModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.activity 2 | 3 | import android.content.Context 4 | import androidx.lifecycle.ViewModel 5 | import androidx.recyclerview.widget.GridLayoutManager 6 | import com.bumptech.glide.RequestManager 7 | import com.sasuke.launcheroneplus.di.mapkey.ViewModelKey 8 | import com.sasuke.launcheroneplus.di.scope.PerActivityScope 9 | import com.sasuke.launcheroneplus.ui.base.SpaceItemDecoration 10 | import com.sasuke.launcheroneplus.ui.wallpaper.list.grid.WallpaperActivityViewModel 11 | import com.sasuke.launcheroneplus.ui.wallpaper.list.grid.WallpaperAdapter 12 | import dagger.Binds 13 | import dagger.Module 14 | import dagger.Provides 15 | import dagger.multibindings.IntoMap 16 | 17 | @Module 18 | abstract class WallpaperActivityModule { 19 | 20 | companion object { 21 | 22 | @Provides 23 | @PerActivityScope 24 | fun adapter(glide: RequestManager): WallpaperAdapter { 25 | return WallpaperAdapter( 26 | glide 27 | ) 28 | } 29 | 30 | @Provides 31 | @PerActivityScope 32 | fun layoutManager(context: Context): GridLayoutManager { 33 | return GridLayoutManager(context, 3) 34 | } 35 | 36 | @Provides 37 | @PerActivityScope 38 | fun itemDecoration(): SpaceItemDecoration { 39 | return SpaceItemDecoration(10, 20) 40 | } 41 | } 42 | 43 | @Binds 44 | @IntoMap 45 | @ViewModelKey(WallpaperActivityViewModel::class) 46 | abstract fun bindWallpaperActivityViewModel(wallpaperActivityViewModel: WallpaperActivityViewModel): ViewModel 47 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/cell_app_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 20 | 21 | 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/ColorUtils.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.content.Context 4 | import androidx.annotation.WorkerThread 5 | import androidx.core.content.ContextCompat 6 | import com.sasuke.launcheroneplus.R 7 | import com.sasuke.launcheroneplus.data.model.DefaultColor 8 | 9 | class ColorUtils(private val context: Context) { 10 | 11 | @WorkerThread 12 | suspend fun getDefaultColorHexList(): MutableList { 13 | val list = ArrayList() 14 | 15 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_one))) 16 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_two))) 17 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_three))) 18 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_four))) 19 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_five))) 20 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_six))) 21 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_seven))) 22 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_eight))) 23 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_nine))) 24 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_ten))) 25 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_eleven))) 26 | list.add(DefaultColor(ContextCompat.getColor(context, R.color.default_search_bar_twelve))) 27 | return list 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/wallpaper/list/grid/WallpaperViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.wallpaper.list.grid 2 | 3 | import android.view.View 4 | import android.widget.ImageView 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.bumptech.glide.RequestManager 7 | import com.bumptech.glide.load.resource.bitmap.CenterCrop 8 | import com.bumptech.glide.load.resource.bitmap.RoundedCorners 9 | import com.bumptech.glide.request.RequestOptions 10 | import com.sasuke.launcheroneplus.R 11 | import com.sasuke.launcheroneplus.data.model.Result 12 | import com.sasuke.launcheroneplus.util.dpToPx 13 | import kotlinx.android.synthetic.main.cell_wallpaper.view.* 14 | 15 | class WallpaperViewHolder(itemView: View, private val glide: RequestManager) : 16 | RecyclerView.ViewHolder(itemView) { 17 | 18 | private lateinit var onItemClickListener: OnItemClickListener 19 | private var requestOptions = RequestOptions() 20 | 21 | init { 22 | requestOptions = requestOptions.transform(CenterCrop(), RoundedCorners(8.dpToPx())) 23 | } 24 | 25 | fun setWallpaper(result: Result) { 26 | glide.load(result.urls.small) 27 | .placeholder(R.drawable.placeholder_big_image) 28 | .apply(requestOptions) 29 | .into(itemView.ivWallpaper) 30 | 31 | itemView.setOnClickListener { 32 | if (::onItemClickListener.isInitialized) 33 | onItemClickListener.onItemClick(adapterPosition, itemView.ivWallpaper) 34 | } 35 | } 36 | 37 | interface OnItemClickListener { 38 | fun onItemClick(position: Int, imageView: ImageView) 39 | } 40 | 41 | fun setOnItemClickListener(onItemClickListener: OnItemClickListener) { 42 | this.onItemClickListener = onItemClickListener 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/wallpaper/list/pager/WallpaperPagerViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.wallpaper.list.pager 2 | 3 | import android.view.View 4 | import android.widget.ImageView 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.bumptech.glide.RequestManager 7 | import com.bumptech.glide.load.resource.bitmap.CenterCrop 8 | import com.bumptech.glide.load.resource.bitmap.RoundedCorners 9 | import com.bumptech.glide.request.RequestOptions 10 | import com.sasuke.launcheroneplus.R 11 | import com.sasuke.launcheroneplus.data.model.Result 12 | import com.sasuke.launcheroneplus.util.dpToPx 13 | import kotlinx.android.synthetic.main.cell_wallpaper_pager.view.* 14 | 15 | class WallpaperPagerViewHolder(itemView: View, private val glide: RequestManager) : 16 | RecyclerView.ViewHolder(itemView) { 17 | 18 | private var requestOptions = RequestOptions() 19 | 20 | init { 21 | requestOptions = requestOptions.transform(CenterCrop(), RoundedCorners(8.dpToPx())) 22 | } 23 | 24 | private lateinit var onItemListener: OnItemListener 25 | 26 | fun setWallpaper(result: Result) { 27 | glide 28 | .load(result.urls.regular) 29 | .placeholder(R.drawable.placeholder_big_image) 30 | .apply(requestOptions) 31 | .dontAnimate() 32 | .into(itemView.ivWallpaper) 33 | 34 | itemView.setOnClickListener { 35 | if (::onItemListener.isInitialized) 36 | onItemListener.onItemClick(adapterPosition, result, itemView.ivWallpaper) 37 | } 38 | } 39 | 40 | interface OnItemListener { 41 | fun onItemClick(position: Int, result: Result, imageView: ImageView) 42 | } 43 | 44 | fun setOnItemListener(onItemListener: OnItemListener) { 45 | this.onItemListener = onItemListener 46 | } 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/settings/LauncherSettingViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.settings 2 | 3 | import android.view.View 4 | import androidx.appcompat.content.res.AppCompatResources 5 | import androidx.core.graphics.drawable.DrawableCompat 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.bumptech.glide.RequestManager 8 | import com.sasuke.launcheroneplus.LauncherApp 9 | import com.sasuke.launcheroneplus.data.model.Setting 10 | import com.sasuke.launcheroneplus.util.updateTint 11 | import kotlinx.android.synthetic.main.cell_setting.view.* 12 | 13 | class LauncherSettingViewHolder(itemView: View, private val glide: RequestManager) : 14 | RecyclerView.ViewHolder(itemView) { 15 | 16 | private lateinit var onItemClickListener: OnItemClickListener 17 | 18 | fun setSettingInfo(setting: Setting) { 19 | if (LauncherApp.color != 0) { 20 | AppCompatResources.getDrawable(itemView.context, setting.icon)?.let { 21 | it.updateTint(LauncherApp.color) 22 | glide 23 | .load(it) 24 | .into(itemView.ivIcon) 25 | } 26 | } else { 27 | glide 28 | .load(setting.icon) 29 | .into(itemView.ivIcon) 30 | } 31 | itemView.tvSettingTitle.text = setting.title 32 | itemView.tvSettingDescription.text = setting.description 33 | 34 | itemView.setOnClickListener { 35 | if (::onItemClickListener.isInitialized) 36 | onItemClickListener.onItemClick(setting) 37 | } 38 | } 39 | 40 | interface OnItemClickListener { 41 | fun onItemClick(setting: Setting) 42 | } 43 | 44 | fun setOnItemClickListener(onItemClickListener: OnItemClickListener) { 45 | this.onItemClickListener = onItemClickListener 46 | } 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/widget/recyclerview_fastscroll/utils/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Tim Malseed 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.sasuke.launcheroneplus.ui.widget.recyclerview_fastscroll.utils; 18 | 19 | import android.annotation.TargetApi; 20 | import android.content.res.Resources; 21 | import android.os.Build; 22 | import android.util.TypedValue; 23 | import android.view.View; 24 | 25 | public class Utils { 26 | 27 | /** 28 | * Converts dp to px 29 | * 30 | * @param res Resources 31 | * @param dp the value in dp 32 | * @return int 33 | */ 34 | public static int toPixels(Resources res, float dp) { 35 | return (int) (dp * res.getDisplayMetrics().density); 36 | } 37 | 38 | /** 39 | * Converts sp to px 40 | * 41 | * @param res Resources 42 | * @param sp the value in sp 43 | * @return int 44 | */ 45 | public static int toScreenPixels(Resources res, float sp) { 46 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, res.getDisplayMetrics()); 47 | } 48 | 49 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 50 | public static boolean isRtl(Resources res) { 51 | return res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/base/MyDragShadowBuilder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.base 2 | 3 | import android.graphics.Canvas 4 | import android.graphics.Point 5 | import android.view.View 6 | import android.widget.ImageView 7 | 8 | class MyDragShadowBuilder(v: View) : View.DragShadowBuilder(v) { 9 | 10 | private var drawable = (v as ImageView).drawable 11 | 12 | init { 13 | drawable = drawable.constantState?.newDrawable()?.mutate() 14 | } 15 | 16 | private val shadow = drawable 17 | 18 | // Defines a callback that sends the drag shadow dimensions and touch point back to the 19 | // system. 20 | override fun onProvideShadowMetrics(size: Point, touch: Point) { 21 | // Sets the width of the shadow to half the width of the original View 22 | val width: Int = (view.width) 23 | 24 | // Sets the height of the shadow to half the height of the original View 25 | val height: Int = (view.height) 26 | 27 | // The drag shadow is a ColorDrawable. This sets its dimensions to be the same as the 28 | // Canvas that the system will provide. As a result, the drag shadow will fill the 29 | // Canvas. 30 | shadow.setBounds(0, 0, width, height) 31 | 32 | // Sets the size parameter's width and height values. These get back to the system 33 | // through the size parameter. 34 | size.set(width, height) 35 | 36 | // Sets the touch point's position to be in the middle of the drag shadow 37 | touch.set((width / 2), (height * 1.5).toInt()) 38 | } 39 | 40 | // Defines a callback that draws the drag shadow in a Canvas that the system constructs 41 | // from the dimensions passed in onProvideShadowMetrics(). 42 | override fun onDrawShadow(canvas: Canvas) { 43 | // Draws the ColorDrawable in the Canvas passed in from the system. 44 | shadow.draw(canvas) 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/data/network/UnsplashRepository.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.data.network 2 | 3 | import com.sasuke.launcheroneplus.data.model.Error 4 | import com.sasuke.launcheroneplus.data.model.Result 5 | import com.sasuke.launcheroneplus.data.model.Wallpaper 6 | import com.sasuke.launcheroneplus.util.ApiCallback 7 | 8 | class UnsplashRepository(private val unsplashService: UnsplashService) { 9 | 10 | fun getWallpapers( 11 | query: String = "Switzerland", 12 | page: Int = 1, 13 | onGetWallpaperListener: OnGetWallpaperListener 14 | ) { 15 | unsplashService.getWallpapersForQuery(query = query, pageNo = page) 16 | .enqueue(object : ApiCallback() { 17 | override fun success(response: Wallpaper) { 18 | onGetWallpaperListener.onGetWallpaperSuccess(response) 19 | } 20 | 21 | override fun failure(error: Error) { 22 | onGetWallpaperListener.onGetWallpaperFailure(error) 23 | } 24 | 25 | }) 26 | } 27 | 28 | fun getPopular(onGetPopularListener: OnGetPopularListener) { 29 | unsplashService.getPopular().enqueue(object : ApiCallback>() { 30 | override fun success(response: List) { 31 | onGetPopularListener.onGetPopularSuccess(response) 32 | } 33 | 34 | override fun failure(error: Error) { 35 | onGetPopularListener.onGetPopularFailure(error) 36 | } 37 | 38 | }) 39 | } 40 | 41 | interface OnGetWallpaperListener { 42 | fun onGetWallpaperSuccess(wallpaper: Wallpaper) 43 | 44 | fun onGetWallpaperFailure(error: Error) 45 | } 46 | 47 | interface OnGetPopularListener { 48 | fun onGetPopularSuccess(list: List) 49 | 50 | fun onGetPopularFailure(error: Error) 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/PackageResolverUtils.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.content.Intent 4 | import android.content.pm.PackageManager 5 | import androidx.annotation.WorkerThread 6 | import com.sasuke.launcheroneplus.data.model.AppInfo 7 | import kotlin.collections.ArrayList 8 | 9 | object PackageResolverUtils { 10 | 11 | @WorkerThread 12 | fun getSortedAppList( 13 | packageManager: PackageManager 14 | ): MutableList { 15 | 16 | val mainIntent = Intent(Intent.ACTION_MAIN, null) 17 | mainIntent.addCategory(Intent.CATEGORY_LAUNCHER) 18 | 19 | val list = packageManager.queryIntentActivities(mainIntent, 0) 20 | val appInoList: MutableList = ArrayList(list.size) 21 | 22 | list.forEach { resolveInfo -> 23 | val packageInfo = AppInfo( 24 | icon = resolveInfo.loadIcon(packageManager), 25 | packageName = resolveInfo.activityInfo.packageName, 26 | label = resolveInfo.loadLabel(packageManager).toString() 27 | ) 28 | appInoList.add(packageInfo) 29 | } 30 | 31 | appInoList.sortBy { 32 | it.label.toLowerCased() 33 | } 34 | 35 | return appInoList 36 | } 37 | 38 | @WorkerThread 39 | fun getAppInfoFromPackageName(packageManager: PackageManager, packageName: String): AppInfo? { 40 | val intent = Intent() 41 | intent.`package` = packageName 42 | intent.addCategory(Intent.CATEGORY_LAUNCHER) 43 | var appInfo: AppInfo? = null 44 | packageManager.resolveActivity(intent, 0)?.let { 45 | appInfo = AppInfo( 46 | icon = it.loadIcon(packageManager), 47 | packageName = it.activityInfo.packageName, 48 | label = it.loadLabel(packageManager).toString() 49 | ) 50 | } 51 | return appInfo 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/settings/LauncherSettingAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.settings 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.bumptech.glide.RequestManager 7 | import com.sasuke.launcheroneplus.R 8 | import com.sasuke.launcheroneplus.data.model.Setting 9 | 10 | class LauncherSettingAdapter(private val glide: RequestManager) : 11 | RecyclerView.Adapter(), 12 | LauncherSettingViewHolder.OnItemClickListener { 13 | 14 | private lateinit var settings: List 15 | private lateinit var onItemClickListener: OnItemClickListener 16 | 17 | 18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LauncherSettingViewHolder { 19 | val view = LayoutInflater.from(parent.context).inflate(R.layout.cell_setting, parent, false) 20 | return LauncherSettingViewHolder(view, glide) 21 | } 22 | 23 | override fun getItemCount(): Int { 24 | return if (::settings.isInitialized) settings.size else 0 25 | } 26 | 27 | override fun onBindViewHolder(holder: LauncherSettingViewHolder, position: Int) { 28 | if (::settings.isInitialized) { 29 | holder.setSettingInfo(settings[position]) 30 | holder.setOnItemClickListener(this) 31 | } 32 | } 33 | 34 | fun setSettings(list: List) { 35 | this.settings = list 36 | notifyDataSetChanged() 37 | } 38 | 39 | override fun onItemClick(setting: Setting) { 40 | if (::onItemClickListener.isInitialized) 41 | onItemClickListener.onItemClick(setting) 42 | } 43 | 44 | interface OnItemClickListener { 45 | fun onItemClick(setting: Setting) 46 | } 47 | 48 | fun setOnItemClickListener(onItemClickListener: OnItemClickListener) { 49 | this.onItemClickListener = onItemClickListener 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #6200EE 4 | #3700B3 5 | @color/search_bar 6 | 7 | 8 | #ff000000 9 | #cc000000 10 | #383838 11 | #212121 12 | #191919 13 | #ffffffff 14 | #46FFFFFF 15 | #66ffffff 16 | #00ffffff 17 | 18 | 19 | @color/black 20 | #80000000 21 | #66ffffff 22 | 23 | 24 | #ff0080ff 25 | #FF6E40 26 | #4d0080ff 27 | #00ffffff 28 | 29 | 30 | 31 | #303960 32 | #2fc4b2 33 | #00adb5 34 | #f08a5d 35 | #b83b5e 36 | #95e1d3 37 | @color/black_transparent 38 | #3f72af 39 | #e84545 40 | #a2d5f2 41 | #769fcd 42 | #ea9a96 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/widget/GridRecyclerView.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.view.animation.GridLayoutAnimationController 8 | import androidx.recyclerview.widget.GridLayoutManager 9 | import androidx.recyclerview.widget.RecyclerView 10 | 11 | class GridRecyclerView : RecyclerView { 12 | 13 | constructor(context: Context) : super(context) 14 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) 15 | constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super( 16 | context, 17 | attrs, 18 | defStyle 19 | ) 20 | 21 | override fun attachLayoutAnimationParameters( 22 | child: View, 23 | params: ViewGroup.LayoutParams, 24 | index: Int, 25 | count: Int 26 | ) { 27 | val adapter = adapter 28 | val layoutManager = layoutManager 29 | if (adapter != null && layoutManager is GridLayoutManager) { 30 | val animationParams = params.layoutAnimationParameters 31 | as? GridLayoutAnimationController.AnimationParameters 32 | ?: GridLayoutAnimationController.AnimationParameters() 33 | params.layoutAnimationParameters = animationParams 34 | 35 | val columns = layoutManager.spanCount 36 | animationParams.count = count 37 | animationParams.index = index 38 | animationParams.columnsCount = columns 39 | animationParams.rowsCount = count / columns 40 | 41 | val invertedIndex = count - 1 - index 42 | animationParams.column = columns - 1 - (invertedIndex % columns) 43 | animationParams.row = animationParams.rowsCount - 1 - invertedIndex / columns 44 | } else { 45 | super.attachLayoutAnimationParameters(child, params, index, count) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/wallpaper/list/grid/WallpaperAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.wallpaper.list.grid 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import android.widget.ImageView 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.bumptech.glide.RequestManager 8 | import com.sasuke.launcheroneplus.R 9 | import com.sasuke.launcheroneplus.data.model.Result 10 | 11 | class WallpaperAdapter(private val glide: RequestManager) : 12 | RecyclerView.Adapter(), WallpaperViewHolder.OnItemClickListener { 13 | 14 | val wallpapers = ArrayList() 15 | private lateinit var onItemClickListener: OnItemClickListener 16 | 17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WallpaperViewHolder { 18 | val view = 19 | LayoutInflater.from(parent.context).inflate(R.layout.cell_wallpaper, parent, false) 20 | val holder = WallpaperViewHolder( 21 | view, 22 | glide 23 | ) 24 | holder.setOnItemClickListener(this) 25 | return holder 26 | } 27 | 28 | override fun getItemCount(): Int { 29 | return wallpapers.size 30 | } 31 | 32 | override fun onBindViewHolder(holder: WallpaperViewHolder, position: Int) { 33 | if (wallpapers.isNotEmpty() && position < wallpapers.size) { 34 | holder.setWallpaper(wallpapers[position]) 35 | } 36 | } 37 | 38 | fun addWallpapers(list: List) { 39 | wallpapers.addAll(list) 40 | } 41 | 42 | override fun onItemClick(position: Int, imageView: ImageView) { 43 | if (::onItemClickListener.isInitialized) 44 | onItemClickListener.onItemClick(position, imageView) 45 | } 46 | 47 | interface OnItemClickListener { 48 | fun onItemClick(position: Int, imageView: ImageView) 49 | } 50 | 51 | fun setOnItemClickListener(onItemClickListener: OnItemClickListener) { 52 | this.onItemClickListener = onItemClickListener 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/ApiCallback.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import com.google.gson.Gson 4 | import retrofit2.Call 5 | import retrofit2.Response 6 | import timber.log.Timber 7 | import com.sasuke.launcheroneplus.data.exception.NoConnectivityException 8 | import com.sasuke.launcheroneplus.data.model.Error 9 | import java.net.UnknownHostException 10 | import javax.net.ssl.SSLHandshakeException 11 | 12 | abstract class ApiCallback : retrofit2.Callback { 13 | 14 | final override fun onResponse(call: Call, response: Response) { 15 | if (response.isSuccessful) { 16 | response.body()?.let { body -> 17 | success(body) 18 | } ?: run { 19 | createError(response) 20 | } 21 | } else { 22 | createError(response) 23 | } 24 | } 25 | 26 | final override fun onFailure(call: Call, t: Throwable) { 27 | Timber.e(t.cause) 28 | var error = Error() 29 | if (t is NoConnectivityException) { 30 | error = Error(true, t.message!!) 31 | failure(error) 32 | } else if (t is SSLHandshakeException) { 33 | error = Error(true, Constants.INTERNET_NOT_WORKING_MESSAGE) 34 | failure(error) 35 | } else if (t is UnknownHostException) { 36 | error = Error(true, Constants.INTERNET_NOT_WORKING_MESSAGE) 37 | failure(error) 38 | } else 39 | failure(error) 40 | } 41 | 42 | private fun createError(response: Response) { 43 | response.errorBody()?.let { errorBody -> 44 | try { 45 | val error = Gson().fromJson(errorBody.string(), Error::class.java) 46 | failure(error) 47 | } catch (e: Exception) { 48 | failure(Error(true, e.localizedMessage)) 49 | } 50 | } ?: run { failure(Error()) } 51 | } 52 | 53 | abstract fun success(response: T) 54 | 55 | abstract fun failure(error: Error) 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/activity/WallpaperPagerActivityModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.activity 2 | 3 | import android.content.Context 4 | import androidx.lifecycle.ViewModel 5 | import androidx.recyclerview.widget.LinearLayoutManager 6 | import androidx.recyclerview.widget.PagerSnapHelper 7 | import androidx.recyclerview.widget.RecyclerView 8 | import com.bumptech.glide.RequestManager 9 | import com.sasuke.launcheroneplus.di.mapkey.ViewModelKey 10 | import com.sasuke.launcheroneplus.di.scope.PerActivityScope 11 | import com.sasuke.launcheroneplus.ui.base.SpaceItemDecoration 12 | import com.sasuke.launcheroneplus.ui.wallpaper.list.pager.WallpaperPagerActivityViewModel 13 | import com.sasuke.launcheroneplus.ui.wallpaper.list.pager.WallpaperPagerAdapter 14 | import dagger.Binds 15 | import dagger.Module 16 | import dagger.Provides 17 | import dagger.multibindings.IntoMap 18 | 19 | @Module 20 | abstract class WallpaperPagerActivityModule { 21 | 22 | companion object { 23 | 24 | @Provides 25 | @PerActivityScope 26 | fun adapter(glide: RequestManager): WallpaperPagerAdapter { 27 | return WallpaperPagerAdapter( 28 | glide 29 | ) 30 | } 31 | 32 | @Provides 33 | @PerActivityScope 34 | fun layoutManager(context: Context): LinearLayoutManager { 35 | return LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) 36 | } 37 | 38 | @Provides 39 | @PerActivityScope 40 | fun itemDecoration(): SpaceItemDecoration { 41 | return SpaceItemDecoration(30, 250) 42 | } 43 | 44 | @Provides 45 | @PerActivityScope 46 | fun pagerSnapHelper(): PagerSnapHelper { 47 | return PagerSnapHelper() 48 | } 49 | } 50 | 51 | @Binds 52 | @IntoMap 53 | @ViewModelKey(WallpaperPagerActivityViewModel::class) 54 | abstract fun bindWallpaperPagerActivityViewModel(wallpaperPagerActivityViewModel: WallpaperPagerActivityViewModel): ViewModel 55 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/settings/set_as_default/DefaultLauncherHandler.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.settings.set_as_default 2 | 3 | import android.annotation.TargetApi 4 | import android.app.Activity 5 | import android.app.role.RoleManager 6 | import android.content.Intent 7 | import android.content.pm.PackageManager 8 | import android.os.Build 9 | import android.provider.Settings 10 | import com.sasuke.launcheroneplus.BuildConfig 11 | import com.sasuke.launcheroneplus.util.GeneralUtils 12 | 13 | abstract class DefaultLauncherHandler(protected val activity: Activity) { 14 | 15 | companion object { 16 | fun create(activity: Activity): DefaultLauncherHandler { 17 | if (GeneralUtils.ATLEAST_Q) { 18 | return DefaultHomeCompatVQ(activity) 19 | } 20 | return DefaultHomeCompatVNMr1(activity) 21 | } 22 | } 23 | 24 | abstract fun isDefaultHome(): Boolean 25 | 26 | fun requestDefaultHome() { 27 | activity.startActivity(Intent(Settings.ACTION_HOME_SETTINGS)) 28 | } 29 | 30 | class DefaultHomeCompatVNMr1(activity: Activity) : DefaultLauncherHandler(activity) { 31 | 32 | override fun isDefaultHome(): Boolean { 33 | return BuildConfig.APPLICATION_ID == resolveDefaultHome() 34 | } 35 | 36 | private fun resolveDefaultHome(): String? { 37 | val homeIntent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) 38 | val info = activity.packageManager 39 | .resolveActivity(homeIntent, PackageManager.MATCH_DEFAULT_ONLY) 40 | return info?.activityInfo?.packageName 41 | } 42 | } 43 | 44 | @TargetApi(Build.VERSION_CODES.Q) 45 | class DefaultHomeCompatVQ(activity: Activity) : DefaultLauncherHandler(activity) { 46 | 47 | private val roleManager = activity.getSystemService(RoleManager::class.java)!! 48 | 49 | override fun isDefaultHome(): Boolean { 50 | return roleManager.isRoleHeld(RoleManager.ROLE_HOME) 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/activity/HiddenAppsActivityModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.activity 2 | 3 | import android.content.Context 4 | import androidx.lifecycle.ViewModel 5 | import androidx.recyclerview.widget.GridLayoutManager 6 | import com.bumptech.glide.RequestManager 7 | import com.sasuke.launcheroneplus.di.mapkey.ViewModelKey 8 | import com.sasuke.launcheroneplus.di.scope.PerActivityScope 9 | import com.sasuke.launcheroneplus.ui.base.BaseEdgeEffectFactory 10 | import com.sasuke.launcheroneplus.ui.base.SpaceItemDecoration 11 | import com.sasuke.launcheroneplus.ui.hidden_apps.HiddenAppsActivityViewModel 12 | import com.sasuke.launcheroneplus.ui.launcher.all_apps.AppAdapter 13 | import com.sasuke.launcheroneplus.util.Constants 14 | import dagger.Binds 15 | import dagger.Module 16 | import dagger.Provides 17 | import dagger.multibindings.IntoMap 18 | 19 | @Module 20 | abstract class HiddenAppsActivityModule { 21 | 22 | companion object { 23 | 24 | @Provides 25 | @PerActivityScope 26 | fun adapter(glide: RequestManager): AppAdapter { 27 | return AppAdapter(glide) 28 | } 29 | 30 | @Provides 31 | @PerActivityScope 32 | fun gridLayoutManager(context: Context): GridLayoutManager { 33 | return GridLayoutManager(context, Constants.APP_LIST_SPAN_COUNT) 34 | } 35 | 36 | @Provides 37 | @PerActivityScope 38 | fun itemDecorator(): SpaceItemDecoration { 39 | return SpaceItemDecoration( 40 | Constants.GRID_HORIZONTAL_SPACING, 41 | Constants.GRID_VERTICAL_SPACING 42 | ) 43 | } 44 | 45 | @Provides 46 | @PerActivityScope 47 | fun baseEdgeEffectFactory(): BaseEdgeEffectFactory { 48 | return BaseEdgeEffectFactory() 49 | } 50 | } 51 | 52 | @Binds 53 | @IntoMap 54 | @ViewModelKey(HiddenAppsActivityViewModel::class) 55 | abstract fun bindHiddenAppsActivityViewModel(hiddenAppsActivityViewModel: HiddenAppsActivityViewModel): ViewModel 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/wallpaper/list/pager/WallpaperPagerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.wallpaper.list.pager 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import android.widget.ImageView 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.bumptech.glide.RequestManager 8 | import com.sasuke.launcheroneplus.R 9 | import com.sasuke.launcheroneplus.data.model.Result 10 | 11 | class WallpaperPagerAdapter(private val glide: RequestManager) : 12 | RecyclerView.Adapter(), WallpaperPagerViewHolder.OnItemListener { 13 | 14 | val wallpapers = ArrayList() 15 | private lateinit var onItemListener: OnItemListener 16 | 17 | 18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WallpaperPagerViewHolder { 19 | val view = 20 | LayoutInflater.from(parent.context) 21 | .inflate(R.layout.cell_wallpaper_pager, parent, false) 22 | val holder = WallpaperPagerViewHolder( 23 | view, 24 | glide 25 | ) 26 | holder.setOnItemListener(this) 27 | return holder 28 | } 29 | 30 | override fun getItemCount(): Int { 31 | return wallpapers.size 32 | } 33 | 34 | override fun onBindViewHolder(holder: WallpaperPagerViewHolder, position: Int) { 35 | if (wallpapers.isNotEmpty() && position < wallpapers.size) { 36 | holder.setWallpaper(wallpapers[position]) 37 | } 38 | } 39 | 40 | fun addWallpapers(list: List) { 41 | wallpapers.addAll(list) 42 | } 43 | 44 | interface OnItemListener { 45 | fun onItemClick(position: Int, result: Result, imageView: ImageView) 46 | } 47 | 48 | fun setOnItemListener(onItemListener: OnItemListener) { 49 | this.onItemListener = onItemListener 50 | } 51 | 52 | override fun onItemClick(position: Int, result: Result, imageView: ImageView) { 53 | if (::onItemListener.isInitialized) 54 | onItemListener.onItemClick(position, result, imageView) 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/receiver/AppChangeReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.receiver 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.Intent 6 | import com.sasuke.launcheroneplus.LauncherApp 7 | import com.sasuke.launcheroneplus.util.AppListUtil 8 | import kotlinx.coroutines.Dispatchers 9 | import kotlinx.coroutines.GlobalScope 10 | import kotlinx.coroutines.launch 11 | import kotlinx.coroutines.withContext 12 | 13 | class AppChangeReceiver : BroadcastReceiver() { 14 | 15 | override fun onReceive(context: Context?, intent: Intent?) { 16 | context?.let { 17 | LauncherApp.get(it.applicationContext).getComponent().getAllListUtils().let { appListUtil -> 18 | intent?.let { intent -> 19 | intent.action?.let { 20 | when (it) { 21 | Intent.ACTION_PACKAGE_ADDED -> { 22 | intent.data?.encodedSchemeSpecificPart?.let { 23 | GlobalScope.launch { 24 | withContext(Dispatchers.IO) { 25 | appListUtil.addAppToDB(it) 26 | } 27 | } 28 | } 29 | } 30 | Intent.ACTION_PACKAGE_REMOVED -> { 31 | intent.data?.encodedSchemeSpecificPart?.let { 32 | GlobalScope.launch { 33 | withContext(Dispatchers.IO) { 34 | appListUtil.removeAppFromDB(it) 35 | } 36 | } 37 | } 38 | } 39 | else -> { 40 | } 41 | } 42 | } 43 | } 44 | 45 | } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_wallpaper_preview.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 24 | 25 | 34 | 35 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/cell_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 20 | 21 | 32 | 33 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/wallpaper/list/pager/WallpaperPagerActivityViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.wallpaper.list.pager 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import com.sasuke.launcheroneplus.data.model.Error 7 | import com.sasuke.launcheroneplus.data.model.Resource 8 | import com.sasuke.launcheroneplus.data.model.Result 9 | import com.sasuke.launcheroneplus.data.model.Wallpaper 10 | import com.sasuke.launcheroneplus.data.network.UnsplashRepository 11 | import javax.inject.Inject 12 | 13 | class WallpaperPagerActivityViewModel @Inject constructor(private val unsplashRepository: UnsplashRepository) : 14 | ViewModel(), UnsplashRepository.OnGetWallpaperListener, 15 | UnsplashRepository.OnGetPopularListener { 16 | 17 | private val _popularWallpaperLiveData = MutableLiveData>>() 18 | val popularWallpaperLiveData: LiveData>> 19 | get() = _popularWallpaperLiveData 20 | 21 | private val _wallpaperLiveData = MutableLiveData>>() 22 | val wallpaperLiveData: LiveData>> 23 | get() = _wallpaperLiveData 24 | 25 | fun getWallpapersForQuery(query: String, page: Int) { 26 | _wallpaperLiveData.postValue(Resource.loading()) 27 | unsplashRepository.getWallpapers(query, page, this) 28 | } 29 | 30 | fun getPopularWalls() { 31 | _popularWallpaperLiveData.postValue(Resource.loading()) 32 | unsplashRepository.getPopular(this) 33 | } 34 | 35 | override fun onGetWallpaperSuccess(wallpaper: Wallpaper) { 36 | _wallpaperLiveData.postValue(Resource.success(wallpaper.results)) 37 | } 38 | 39 | override fun onGetWallpaperFailure(error: Error) { 40 | _wallpaperLiveData.postValue(Resource.error(error)) 41 | } 42 | 43 | override fun onGetPopularSuccess(list: List) { 44 | _popularWallpaperLiveData.postValue(Resource.success(list)) 45 | } 46 | 47 | override fun onGetPopularFailure(error: Error) { 48 | _popularWallpaperLiveData.postValue(Resource.error(error)) 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/KeyboardTriggerBehavior.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.app.Activity 4 | import android.graphics.Rect 5 | import android.view.View 6 | import android.view.ViewTreeObserver 7 | import androidx.lifecycle.LifecycleOwner 8 | import androidx.lifecycle.LiveData 9 | import androidx.lifecycle.Observer 10 | 11 | open class KeyboardTriggerBehavior(activity: Activity, private val minKeyboardHeight: Int = 0) : LiveData() { 12 | enum class Status { 13 | OPEN, CLOSED 14 | } 15 | 16 | private val contentView: View = activity.findViewById(android.R.id.content) 17 | 18 | private val globalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener { 19 | val displayRect = Rect().apply { contentView.getWindowVisibleDisplayFrame(this) } 20 | val keypadHeight = contentView.rootView.height - displayRect.bottom 21 | if (keypadHeight > minKeyboardHeight) { 22 | setDistinctValue(Status.OPEN) 23 | } else { 24 | setDistinctValue(Status.CLOSED) 25 | } 26 | } 27 | 28 | override fun observe(owner: LifecycleOwner, observer: Observer) { 29 | super.observe(owner, observer) 30 | observersUpdated() 31 | } 32 | 33 | override fun observeForever(observer: Observer) { 34 | super.observeForever(observer) 35 | observersUpdated() 36 | } 37 | 38 | override fun removeObservers(owner: LifecycleOwner) { 39 | super.removeObservers(owner) 40 | observersUpdated() 41 | } 42 | 43 | override fun removeObserver(observer: Observer) { 44 | super.removeObserver(observer) 45 | observersUpdated() 46 | } 47 | 48 | private fun setDistinctValue(newValue: Status) { 49 | if (value != newValue) { 50 | value = newValue 51 | } 52 | } 53 | 54 | private fun observersUpdated() { 55 | if (hasObservers()) { 56 | contentView.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener) 57 | } else { 58 | contentView.viewTreeObserver.removeOnGlobalLayoutListener(globalLayoutListener) 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/SharedPreferencesSettingsLiveData.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.content.SharedPreferences 4 | import android.text.TextUtils 5 | import androidx.lifecycle.LiveData 6 | import com.google.gson.Gson 7 | import com.sasuke.launcheroneplus.data.model.SettingPreference 8 | 9 | class SharedPreferencesSettingsLiveData( 10 | sharedPrefs: SharedPreferences, 11 | private val gson: Gson 12 | ) : 13 | SharedPreferencesLiveData(sharedPrefs) { 14 | 15 | private fun getString(key: String, default: String): String { 16 | sharedPrefs.getString(key, default)?.let { 17 | return it 18 | } ?: run { 19 | return "" 20 | } 21 | } 22 | 23 | private fun getString(key: String): String { 24 | return getString(key, "") 25 | } 26 | 27 | override fun getValueFromPreferences(key: String): SettingPreference? { 28 | var user: SettingPreference? = null 29 | try { 30 | val userString = getString(Constants.PREFERENCES) 31 | if (!TextUtils.isEmpty(userString)) { 32 | user = gson.fromJson(userString, SettingPreference::class.java) 33 | } 34 | } catch (e: Exception) { 35 | e.printStackTrace() 36 | } finally { 37 | return user 38 | } 39 | } 40 | } 41 | 42 | abstract class SharedPreferencesLiveData(val sharedPrefs: SharedPreferences) : LiveData() { 43 | private val preferenceChangeListener = 44 | SharedPreferences.OnSharedPreferenceChangeListener { _, key -> 45 | if (key == Constants.PREFERENCES) { 46 | value = getValueFromPreferences(key) 47 | } 48 | } 49 | 50 | abstract fun getValueFromPreferences(key: String): T? 51 | 52 | override fun onActive() { 53 | super.onActive() 54 | value = getValueFromPreferences(Constants.PREFERENCES) 55 | sharedPrefs.registerOnSharedPreferenceChangeListener(preferenceChangeListener) 56 | } 57 | 58 | override fun onInactive() { 59 | sharedPrefs.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener) 60 | super.onInactive() 61 | } 62 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/Extensions.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.content.Context 4 | import android.content.pm.ApplicationInfo 5 | import android.content.res.Resources 6 | import android.graphics.drawable.Drawable 7 | import android.view.View 8 | import androidx.core.graphics.drawable.DrawableCompat 9 | import androidx.core.view.WindowInsetsCompat 10 | import androidx.recyclerview.widget.RecyclerView 11 | import java.io.File 12 | import java.util.* 13 | 14 | fun String.toLowerCased(): String = this.toLowerCase(Locale.getDefault()) 15 | 16 | inline fun RecyclerView.forEachVisibleHolder( 17 | action: (T) -> Unit 18 | ) { 19 | for (i in 0 until childCount) { 20 | action(getChildViewHolder(getChildAt(i)) as T) 21 | } 22 | } 23 | 24 | fun Drawable.updateTint(color: Int) { 25 | DrawableCompat.wrap(this)?.let { 26 | DrawableCompat.setTint(it, color) 27 | } 28 | } 29 | 30 | fun Context.getIconFolderPath(label: String): String { 31 | return "${applicationContext.getExternalFilesDir(Constants.ICON_FOLDER_NAME)}${File.separator}${label.removeSpecialChars()}" 32 | } 33 | 34 | fun isSystemApp(context: Context, packageName: String): Boolean { 35 | val appInfo = context.applicationContext.packageManager.getApplicationInfo(packageName, 0) 36 | return (appInfo.flags and ApplicationInfo.FLAG_SYSTEM) != 0 37 | } 38 | 39 | fun String.removeSpecialChars(): String { 40 | return replace( 41 | "[\\W]|_".toRegex(), 42 | "" 43 | ) 44 | } 45 | 46 | fun View.hide() { 47 | this.visibility = View.GONE 48 | } 49 | 50 | fun View.show() { 51 | this.visibility = View.VISIBLE 52 | } 53 | 54 | fun Int.dpToPx(): Int { 55 | return (this * Resources.getSystem().displayMetrics.density).toInt() 56 | } 57 | 58 | fun Int.alphaPercentage(): Int { 59 | return ((this.toDouble() / 100.0) * 255.0).toInt() 60 | } 61 | 62 | val View.keyboardIsVisible: Boolean 63 | get() = WindowInsetsCompat 64 | .toWindowInsetsCompat(rootWindowInsets) 65 | .isVisible(WindowInsetsCompat.Type.ime()) 66 | 67 | fun T.removeItemDecorations() { 68 | while (itemDecorationCount > 0) { 69 | removeItemDecorationAt(0) 70 | } 71 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/wallpaper/list/grid/WallpaperActivityViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.wallpaper.list.grid 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import com.sasuke.launcheroneplus.data.model.Error 7 | import com.sasuke.launcheroneplus.data.model.Resource 8 | import com.sasuke.launcheroneplus.data.model.Result 9 | import com.sasuke.launcheroneplus.data.model.Wallpaper 10 | import com.sasuke.launcheroneplus.data.network.UnsplashRepository 11 | import javax.inject.Inject 12 | 13 | class WallpaperActivityViewModel @Inject constructor(private val unsplashRepository: UnsplashRepository) : 14 | ViewModel(), UnsplashRepository.OnGetWallpaperListener, 15 | UnsplashRepository.OnGetPopularListener { 16 | 17 | var page = 1 18 | 19 | private val _popularWallpaperLiveData = MutableLiveData>>() 20 | val popularWallpaperLiveData: LiveData>> 21 | get() = _popularWallpaperLiveData 22 | 23 | private val _wallpaperLiveData = MutableLiveData>>() 24 | val wallpaperLiveData: LiveData>> 25 | get() = _wallpaperLiveData 26 | 27 | fun getWallpapersForQuery(query: String) { 28 | _wallpaperLiveData.postValue(Resource.loading()) 29 | unsplashRepository.getWallpapers(query, page, this) 30 | } 31 | 32 | fun getPopularWalls() { 33 | _popularWallpaperLiveData.postValue(Resource.loading()) 34 | unsplashRepository.getPopular(this) 35 | } 36 | 37 | fun refresh() { 38 | page = 1 39 | } 40 | 41 | override fun onGetWallpaperSuccess(wallpaper: Wallpaper) { 42 | page++ 43 | _wallpaperLiveData.postValue(Resource.success(wallpaper.results)) 44 | } 45 | 46 | override fun onGetWallpaperFailure(error: Error) { 47 | _wallpaperLiveData.postValue(Resource.error(error)) 48 | } 49 | 50 | override fun onGetPopularSuccess(list: List) { 51 | _popularWallpaperLiveData.postValue(Resource.success(list)) 52 | } 53 | 54 | override fun onGetPopularFailure(error: Error) { 55 | _popularWallpaperLiveData.postValue(Resource.error(error)) 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/util/AppListUtil.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.util 2 | 3 | import android.content.Context 4 | import android.content.pm.PackageManager 5 | import androidx.annotation.WorkerThread 6 | import com.sasuke.launcheroneplus.data.db.RoomRepository 7 | import com.sasuke.launcheroneplus.data.model.App 8 | import javax.inject.Inject 9 | 10 | class AppListUtil @Inject constructor( 11 | private val roomRepository: RoomRepository, 12 | private val bitmapUtils: BitmapUtils, 13 | private val storageUtils: StorageUtils, 14 | private val packageManager: PackageManager, 15 | private val context: Context 16 | ) { 17 | 18 | @WorkerThread 19 | suspend fun saveAppsInDB() { 20 | if (roomRepository.isAppsInDB() <= 0) { 21 | val list = PackageResolverUtils.getSortedAppList(packageManager) 22 | list.forEach { appInfo -> 23 | bitmapUtils.drawableToBitmap(appInfo.icon)?.let { 24 | if (appInfo.packageName != context.packageName) { 25 | storageUtils.saveBitmapToFile(it, appInfo.label) 26 | roomRepository.insert( 27 | App( 28 | packageName = appInfo.packageName, 29 | label = appInfo.label 30 | ) 31 | ) 32 | } 33 | } 34 | } 35 | } 36 | } 37 | 38 | @WorkerThread 39 | suspend fun removeAppFromDB(packageName: String) { 40 | roomRepository.deleteApp(packageName) 41 | } 42 | 43 | @WorkerThread 44 | suspend fun addAppToDB(packageName: String) { 45 | PackageResolverUtils.getAppInfoFromPackageName(packageManager, packageName) 46 | ?.let { appInfo -> 47 | bitmapUtils.drawableToBitmap(appInfo.icon)?.let { 48 | storageUtils.saveBitmapToFile(it, appInfo.label) 49 | roomRepository.insert( 50 | App( 51 | packageName = appInfo.packageName, 52 | label = appInfo.label 53 | ) 54 | ) 55 | } 56 | } 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_wallpaper_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 26 | 27 | 38 | 39 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/cell_app_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 24 | 25 | 38 | 39 | 58 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/activity/ActivityBindingModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.activity 2 | 3 | import com.sasuke.launcheroneplus.ui.launcher.LauncherActivity 4 | import com.sasuke.launcheroneplus.di.scope.PerActivityScope 5 | import com.sasuke.launcheroneplus.ui.hidden_apps.HiddenAppsActivity 6 | import com.sasuke.launcheroneplus.ui.hidden_apps.app_selector.AppSelectionActivity 7 | import com.sasuke.launcheroneplus.ui.screen_off.ScreenOffActivity 8 | import com.sasuke.launcheroneplus.ui.settings.LauncherSettingsActivity 9 | import com.sasuke.launcheroneplus.ui.settings.app_drawer.AppDrawerActivity 10 | import com.sasuke.launcheroneplus.ui.wallpaper.WallpaperPreviewActivity 11 | import com.sasuke.launcheroneplus.ui.wallpaper.list.grid.WallpaperGridActivity 12 | import com.sasuke.launcheroneplus.ui.wallpaper.list.pager.WallpaperPagerActivity 13 | import dagger.Module 14 | import dagger.android.ContributesAndroidInjector 15 | 16 | @Module(includes = []) 17 | abstract class ActivityBindingModule { 18 | 19 | @PerActivityScope 20 | @ContributesAndroidInjector(modules = [LauncherActivityModule::class]) 21 | internal abstract fun mainActivity(): LauncherActivity 22 | 23 | @PerActivityScope 24 | @ContributesAndroidInjector(modules = [HiddenAppsActivityModule::class]) 25 | internal abstract fun hiddenAppsActivity(): HiddenAppsActivity 26 | 27 | @PerActivityScope 28 | @ContributesAndroidInjector(modules = [AppSelectionActivityModule::class]) 29 | internal abstract fun appSelectionActivity(): AppSelectionActivity 30 | 31 | @PerActivityScope 32 | @ContributesAndroidInjector(modules = []) 33 | internal abstract fun screenOffActivity(): ScreenOffActivity 34 | 35 | @PerActivityScope 36 | @ContributesAndroidInjector(modules = [WallpaperActivityModule::class]) 37 | internal abstract fun wallpaperSettingsActivity(): WallpaperGridActivity 38 | 39 | @PerActivityScope 40 | @ContributesAndroidInjector(modules = [WallpaperPagerActivityModule::class]) 41 | internal abstract fun wallpaperPagerActivity(): WallpaperPagerActivity 42 | 43 | @PerActivityScope 44 | @ContributesAndroidInjector(modules = []) 45 | internal abstract fun wallpaperPreviewActivity(): WallpaperPreviewActivity 46 | 47 | @PerActivityScope 48 | @ContributesAndroidInjector(modules = [LauncherSettingsActivityModule::class]) 49 | internal abstract fun launcherSettingsActivity(): LauncherSettingsActivity 50 | 51 | @PerActivityScope 52 | @ContributesAndroidInjector(modules = [AppDrawerActivityModule::class]) 53 | internal abstract fun appDrawerActivity(): AppDrawerActivity 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/component/LauncherAppComponent.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.component 2 | 3 | import android.content.Context 4 | import com.bumptech.glide.RequestManager 5 | import com.google.gson.Gson 6 | import com.sasuke.launcheroneplus.LauncherApp 7 | import com.sasuke.launcheroneplus.data.db.RoomRepository 8 | import com.sasuke.launcheroneplus.data.network.UnsplashRepository 9 | import com.sasuke.launcheroneplus.di.scope.LauncherAppScope 10 | import com.sasuke.launcheroneplus.di.module.util.ViewModelFactoryModule 11 | import com.sasuke.launcheroneplus.di.module.activity.ActivityBindingModule 12 | import com.sasuke.launcheroneplus.di.module.application.LauncherApplicationModule 13 | import com.sasuke.launcheroneplus.di.module.library.GlideModule 14 | import com.sasuke.launcheroneplus.di.module.network.UnsplashRepositoryModule 15 | import com.sasuke.launcheroneplus.di.module.util.SharedPreferenceModule 16 | import com.sasuke.launcheroneplus.di.module.util.UtilsModule 17 | import com.sasuke.launcheroneplus.util.* 18 | import dagger.BindsInstance 19 | import dagger.Component 20 | import dagger.android.AndroidInjector 21 | import dagger.android.support.AndroidSupportInjectionModule 22 | import io.github.inflationx.calligraphy3.CalligraphyInterceptor 23 | import timber.log.Timber 24 | 25 | @LauncherAppScope 26 | @Component( 27 | modules = [ 28 | LauncherApplicationModule::class, 29 | UnsplashRepositoryModule::class, 30 | GlideModule::class, 31 | UtilsModule::class, 32 | SharedPreferenceModule::class, 33 | AndroidSupportInjectionModule::class, 34 | ViewModelFactoryModule::class, 35 | ActivityBindingModule::class] 36 | ) 37 | interface LauncherAppComponent : AndroidInjector { 38 | 39 | @Component.Factory 40 | interface Factory { 41 | fun create(@BindsInstance applicationContext: Context): LauncherAppComponent 42 | } 43 | 44 | fun context(): Context 45 | 46 | fun glide(): RequestManager 47 | 48 | fun getStorageUtil(): StorageUtils 49 | 50 | fun getBitmapUtils(): BitmapUtils 51 | 52 | fun getRoomRepository(): RoomRepository 53 | 54 | fun getAllListUtils(): AppListUtil 55 | 56 | fun getUnsplashRepository(): UnsplashRepository 57 | 58 | fun timberTree(): Timber.Tree 59 | 60 | fun calligraphyInterceptor(): CalligraphyInterceptor 61 | 62 | fun getSettingUtils(): SettingUtils 63 | 64 | fun getColorUtils(): ColorUtils 65 | 66 | fun getSharedPreferenceUtil(): SharedPreferenceUtil 67 | 68 | fun getSharedPreferencesSettingsLiveData(): SharedPreferencesSettingsLiveData 69 | 70 | fun gson(): Gson 71 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/di/module/activity/AppSelectionActivityModule.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.di.module.activity 2 | 3 | import android.content.Context 4 | import androidx.lifecycle.ViewModel 5 | import androidx.recyclerview.widget.GridLayoutManager 6 | import com.bumptech.glide.RequestManager 7 | import com.sasuke.launcheroneplus.di.mapkey.ViewModelKey 8 | import com.sasuke.launcheroneplus.di.qualifiers.HiddenAppLayoutManager 9 | import com.sasuke.launcheroneplus.di.qualifiers.VisibleAppLayoutManager 10 | import com.sasuke.launcheroneplus.di.scope.PerActivityScope 11 | import com.sasuke.launcheroneplus.ui.base.SpaceItemDecoration 12 | import com.sasuke.launcheroneplus.ui.hidden_apps.app_selector.AppSelectionActivityViewModel 13 | import com.sasuke.launcheroneplus.ui.hidden_apps.app_selector.HiddenAppSelectionAdapter 14 | import com.sasuke.launcheroneplus.ui.hidden_apps.app_selector.VisibleAppSelectionAdapter 15 | import com.sasuke.launcheroneplus.util.Constants 16 | import dagger.Binds 17 | import dagger.Module 18 | import dagger.Provides 19 | import dagger.multibindings.IntoMap 20 | 21 | @Module 22 | abstract class AppSelectionActivityModule { 23 | 24 | companion object { 25 | 26 | @Provides 27 | @PerActivityScope 28 | fun hiddenAppSelectionAdapter(glide: RequestManager): HiddenAppSelectionAdapter { 29 | return HiddenAppSelectionAdapter(glide) 30 | } 31 | 32 | @Provides 33 | @PerActivityScope 34 | fun visibleAppSelectionAdapter(glide: RequestManager): VisibleAppSelectionAdapter { 35 | return VisibleAppSelectionAdapter(glide) 36 | } 37 | 38 | @Provides 39 | @PerActivityScope 40 | @HiddenAppLayoutManager 41 | fun gridLayoutManager1(context: Context): GridLayoutManager { 42 | return GridLayoutManager(context, Constants.APP_LIST_SPAN_COUNT) 43 | } 44 | 45 | @Provides 46 | @PerActivityScope 47 | @VisibleAppLayoutManager 48 | fun gridLayoutManager2(context: Context): GridLayoutManager { 49 | return GridLayoutManager(context, Constants.APP_LIST_SPAN_COUNT) 50 | } 51 | 52 | @Provides 53 | @PerActivityScope 54 | fun itemDecorator(): SpaceItemDecoration { 55 | return SpaceItemDecoration( 56 | Constants.GRID_HORIZONTAL_SPACING, 57 | Constants.GRID_VERTICAL_SPACING 58 | ) 59 | } 60 | } 61 | 62 | @Binds 63 | @IntoMap 64 | @ViewModelKey(AppSelectionActivityViewModel::class) 65 | abstract fun bindAppSelectionActivityViewModel(appSelectionActivityViewModel: AppSelectionActivityViewModel): ViewModel 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/drag_drop/GridViewAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.drag_drop 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import android.widget.BaseAdapter 7 | import com.bumptech.glide.RequestManager 8 | import com.huxq17.handygridview.scrollrunner.OnItemMovedListener 9 | import com.sasuke.launcheroneplus.R 10 | import com.sasuke.launcheroneplus.data.model.App 11 | 12 | class GridViewAdapter(private val glide: RequestManager) : BaseAdapter(), OnItemMovedListener, 13 | GridAppViewHolder.OnClickListeners { 14 | 15 | private lateinit var onClickListeners: OnClickListeners 16 | private val list: MutableList = ArrayList() 17 | private var inEditMode = false 18 | 19 | companion object { 20 | private const val MAX_ALLOWED_SHORTCUTS = 19 21 | } 22 | 23 | override fun getView(position: Int, convertview: View?, parent: ViewGroup): View { 24 | val appViewHolder: GridAppViewHolder 25 | val myView: View = 26 | convertview 27 | ?: LayoutInflater.from(parent.context).inflate( 28 | R.layout.cell_app_info, 29 | parent, 30 | false 31 | ) 32 | appViewHolder = GridAppViewHolder(myView, glide) 33 | appViewHolder.setAppInfo(getItem(position) as App) 34 | appViewHolder.setOnClickListeners(this) 35 | return myView 36 | } 37 | 38 | override fun getItem(position: Int): Any { 39 | return list[position] 40 | } 41 | 42 | override fun getItemId(position: Int): Long { 43 | return position.toLong() 44 | } 45 | 46 | override fun getCount(): Int { 47 | return list.size 48 | } 49 | 50 | override fun onItemMoved(from: Int, to: Int) { 51 | val appInfo = list.removeAt(from) 52 | list.add(to, appInfo) 53 | } 54 | 55 | override fun isFixed(position: Int): Boolean { 56 | return false 57 | } 58 | 59 | fun addItem(appInfo: App) { 60 | if (list.size > MAX_ALLOWED_SHORTCUTS) 61 | list.removeAt(0) 62 | list.add(appInfo) 63 | notifyDataSetChanged() 64 | } 65 | 66 | fun setInEditMode(inEditMode: Boolean) { 67 | this.inEditMode = inEditMode 68 | notifyDataSetChanged() 69 | } 70 | 71 | interface OnClickListeners { 72 | fun onItemClick(position: Int, parent: View, appInfo: App) 73 | } 74 | 75 | fun setOnClickListeners(onClickListeners: OnClickListeners) { 76 | this.onClickListeners = onClickListeners 77 | } 78 | 79 | override fun onItemClick(position: Int, parent: View, appInfo: App) { 80 | if (::onClickListeners.isInitialized) 81 | onClickListeners.onItemClick(position, parent, appInfo) 82 | } 83 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/color_picker/ColorAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.color_picker 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.bumptech.glide.RequestManager 7 | import com.sasuke.launcheroneplus.R 8 | import com.sasuke.launcheroneplus.data.model.DefaultColor 9 | 10 | class ColorAdapter : RecyclerView.Adapter(), 11 | ColorViewHolder.OnClickListeners { 12 | 13 | private lateinit var colors: List 14 | private lateinit var onClickListeners: OnClickListeners 15 | 16 | private var position = -1 17 | 18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ColorViewHolder { 19 | val view = 20 | LayoutInflater.from(parent.context).inflate(R.layout.cell_default_color, parent, false) 21 | val holder = ColorViewHolder(view) 22 | holder.setOnClickListeners(this) 23 | return holder 24 | } 25 | 26 | override fun getItemCount(): Int { 27 | return if (::colors.isInitialized) colors.size else 0 28 | } 29 | 30 | override fun onBindViewHolder(holder: ColorViewHolder, position: Int) { 31 | if (::colors.isInitialized) { 32 | holder.setColor(colors[position]) 33 | } 34 | } 35 | 36 | override fun onBindViewHolder( 37 | holder: ColorViewHolder, 38 | position: Int, 39 | payloads: MutableList 40 | ) { 41 | if (::colors.isInitialized) { 42 | if (payloads.isNotEmpty()) { 43 | val flag = payloads[0] as Boolean 44 | holder.toggle(flag) 45 | } else { 46 | super.onBindViewHolder(holder, position, payloads) 47 | } 48 | } 49 | } 50 | 51 | interface OnClickListeners { 52 | fun onItemClick(position: Int, color: Int) 53 | } 54 | 55 | fun setOnClickListeners(onClickListeners: OnClickListeners) { 56 | this.onClickListeners = onClickListeners 57 | } 58 | 59 | override fun onItemClick(position: Int, color: Int) { 60 | if (::onClickListeners.isInitialized) 61 | onClickListeners.onItemClick(position, color) 62 | } 63 | 64 | fun setColors(list: List) { 65 | this.colors = list 66 | notifyDataSetChanged() 67 | } 68 | 69 | fun toggle(position: Int): Boolean { 70 | if (this.position != -1 && this.position != position) { 71 | colors[this.position].isSelected = false 72 | notifyItemChanged(this.position, false) 73 | this.position = position 74 | } else { 75 | this.position = position 76 | } 77 | var flag = colors[position].isSelected 78 | flag = !flag 79 | colors[position].isSelected = flag 80 | notifyItemChanged(position, flag) 81 | return flag 82 | } 83 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/launcher/recent_apps/RecentAppAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.launcher.recent_apps 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.core.view.doOnLayout 7 | import androidx.recyclerview.widget.DiffUtil 8 | import androidx.recyclerview.widget.ListAdapter 9 | import com.bumptech.glide.RequestManager 10 | import com.sasuke.launcheroneplus.R 11 | import com.sasuke.launcheroneplus.data.model.App 12 | import com.sasuke.launcheroneplus.ui.launcher.all_apps.AppViewHolder 13 | import com.sasuke.launcheroneplus.util.OnCustomEventListeners 14 | 15 | class RecentAppAdapter(private val glide: RequestManager) : 16 | ListAdapter(appItemDiffCallback), OnCustomEventListeners { 17 | 18 | private lateinit var onClickListeners: OnCustomEventListeners 19 | 20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder { 21 | val view = 22 | LayoutInflater.from(parent.context).inflate(R.layout.cell_app_info, parent, false) 23 | return AppViewHolder(view, glide).apply { 24 | // The rotation pivot should be at the center of the top edge. 25 | itemView.doOnLayout { v -> v.pivotX = v.width / 2f } 26 | itemView.pivotY = 0f 27 | setOnCustomEventListeners(this@RecentAppAdapter) 28 | } 29 | } 30 | 31 | override fun onBindViewHolder(holder: AppViewHolder, position: Int) { 32 | getItem(position)?.let { 33 | holder.setAppInfo(it) 34 | } 35 | } 36 | 37 | fun setOnClickListeners(onClickListeners: OnCustomEventListeners) { 38 | this.onClickListeners = onClickListeners 39 | } 40 | 41 | override fun onItemClick(position: Int, parent: View, appInfo: App) { 42 | if (::onClickListeners.isInitialized) 43 | onClickListeners.onItemClick(position, parent, appInfo) 44 | } 45 | 46 | override fun onItemLongClick(position: Int, parent: View, appInfo: App) { 47 | if (::onClickListeners.isInitialized) 48 | onClickListeners.onItemLongClick(position, parent, appInfo) 49 | } 50 | 51 | override fun onDragStart(position: Int, parent: View, appInfo: App) { 52 | if (::onClickListeners.isInitialized) 53 | onClickListeners.onDragStart(position, parent, appInfo) 54 | } 55 | 56 | override fun onEventCancel(position: Int, appInfo: App) { 57 | if (::onClickListeners.isInitialized) 58 | onClickListeners.onEventCancel(position, appInfo) 59 | } 60 | } 61 | 62 | private val appItemDiffCallback = object : DiffUtil.ItemCallback() { 63 | override fun areItemsTheSame(oldItem: App, newItem: App): Boolean { 64 | return oldItem.packageName == newItem.packageName 65 | } 66 | 67 | override fun areContentsTheSame(oldItem: App, newItem: App): Boolean { 68 | return oldItem == newItem 69 | } 70 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/launcher/recent_apps/RecentAppSectionViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.launcher.recent_apps 2 | 3 | import android.view.View 4 | import androidx.recyclerview.widget.GridLayoutManager 5 | import androidx.recyclerview.widget.LinearLayoutManager 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.bumptech.glide.RequestManager 8 | import com.sasuke.launcheroneplus.data.model.App 9 | import com.sasuke.launcheroneplus.data.model.DrawerStyle 10 | import com.sasuke.launcheroneplus.ui.base.BaseViewHolder 11 | import com.sasuke.launcheroneplus.util.Constants 12 | import com.sasuke.launcheroneplus.util.OnCustomEventListeners 13 | import com.sasuke.launcheroneplus.util.hide 14 | import com.sasuke.launcheroneplus.util.show 15 | import kotlinx.android.synthetic.main.cell_recent_app_section.view.* 16 | 17 | class RecentAppSectionViewHolder( 18 | itemView: View, 19 | private val glide: RequestManager, 20 | private val drawerStyle: DrawerStyle 21 | ) : 22 | BaseViewHolder(itemView), OnCustomEventListeners { 23 | 24 | private lateinit var recentAppAdapter: RecentAppAdapter 25 | private lateinit var onCustomEventListeners: OnCustomEventListeners 26 | 27 | fun setRecentApps(list: List) { 28 | when (drawerStyle) { 29 | DrawerStyle.VERTICAL -> { 30 | itemView.separator.show() 31 | } 32 | DrawerStyle.LIST -> { 33 | itemView.separator.hide() 34 | } 35 | } 36 | itemView.rvRecentApps.layoutManager = 37 | GridLayoutManager( 38 | itemView.context, 39 | Constants.APP_LIST_SPAN_COUNT, 40 | RecyclerView.VERTICAL, 41 | false 42 | ) 43 | recentAppAdapter = RecentAppAdapter(glide) 44 | recentAppAdapter.setOnClickListeners(this) 45 | itemView.rvRecentApps.adapter = recentAppAdapter 46 | recentAppAdapter.submitList(list) 47 | } 48 | 49 | fun setOnCustomEventListener(onCustomEventListeners: OnCustomEventListeners) { 50 | this.onCustomEventListeners = onCustomEventListeners 51 | } 52 | 53 | override fun onItemClick(position: Int, parent: View, appInfo: App) { 54 | if (::onCustomEventListeners.isInitialized) 55 | onCustomEventListeners.onItemClick(position, parent, appInfo) 56 | } 57 | 58 | override fun onItemLongClick(position: Int, parent: View, appInfo: App) { 59 | if (::onCustomEventListeners.isInitialized) 60 | onCustomEventListeners.onItemLongClick(position, parent, appInfo) 61 | } 62 | 63 | override fun onDragStart(position: Int, parent: View, appInfo: App) { 64 | if (::onCustomEventListeners.isInitialized) 65 | onCustomEventListeners.onDragStart(position, parent, appInfo) 66 | } 67 | 68 | override fun onEventCancel(position: Int, appInfo: App) { 69 | if (::onCustomEventListeners.isInitialized) 70 | onCustomEventListeners.onEventCancel(position, appInfo) 71 | } 72 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/hidden_apps/app_selector/HiddenAppSelectionAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.hidden_apps.app_selector 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.bumptech.glide.RequestManager 7 | import com.sasuke.launcheroneplus.R 8 | import com.sasuke.launcheroneplus.data.model.App 9 | 10 | class HiddenAppSelectionAdapter(private val glide: RequestManager) : 11 | RecyclerView.Adapter(), 12 | HiddenAppSelectionViewHolder.OnClickListeners { 13 | 14 | private lateinit var onClickListeners: OnClickListeners 15 | private lateinit var appList: MutableList 16 | 17 | init { 18 | setHasStableIds(true) 19 | } 20 | 21 | override fun onCreateViewHolder( 22 | parent: ViewGroup, 23 | viewType: Int 24 | ): HiddenAppSelectionViewHolder { 25 | val view = 26 | LayoutInflater.from(parent.context).inflate(R.layout.cell_app_selector, parent, false) 27 | val holderHidden = HiddenAppSelectionViewHolder(view, glide) 28 | holderHidden.setOnClickListeners(this) 29 | return holderHidden 30 | } 31 | 32 | override fun getItemCount(): Int { 33 | return if (::appList.isInitialized) appList.size else 0 34 | } 35 | 36 | override fun onBindViewHolder(holderHidden: HiddenAppSelectionViewHolder, position: Int) { 37 | if (::appList.isInitialized) { 38 | holderHidden.setApp(appList[position]) 39 | } 40 | } 41 | 42 | override fun onBindViewHolder( 43 | holderHidden: HiddenAppSelectionViewHolder, 44 | position: Int, 45 | payloads: MutableList 46 | ) { 47 | super.onBindViewHolder(holderHidden, position, payloads) 48 | if (payloads.isNotEmpty()) { 49 | val flag = payloads[0] 50 | if (flag is Boolean) { 51 | holderHidden.toggle(flag) 52 | } 53 | } 54 | } 55 | 56 | override fun getItemId(position: Int): Long { 57 | return position.toLong() 58 | } 59 | 60 | interface OnClickListeners { 61 | fun onHiddenItemClick(position: Int, appInfo: App) 62 | } 63 | 64 | fun setApps(list: MutableList) { 65 | this.appList = list 66 | notifyDataSetChanged() 67 | } 68 | 69 | fun toggle(position: Int) { 70 | var flag = appList[position].isHidden 71 | flag = !flag 72 | appList[position].isHidden = flag 73 | notifyItemChanged(position, flag) 74 | } 75 | 76 | fun setOnClickListeners(onClickListeners: OnClickListeners) { 77 | this.onClickListeners = onClickListeners 78 | } 79 | 80 | override fun onHiddenItemClick(position: Int, appInfo: App) { 81 | if (::onClickListeners.isInitialized) 82 | onClickListeners.onHiddenItemClick(position, appInfo) 83 | } 84 | 85 | // override fun getSectionText(position: Int): CharSequence { 86 | // return appList[position].label[0].toUpperCase().toString() 87 | // } 88 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sasuke/launcheroneplus/ui/settings/app_drawer/AppDrawerActivityViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.sasuke.launcheroneplus.ui.settings.app_drawer 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.google.gson.Gson 6 | import com.sasuke.launcheroneplus.data.model.DrawerStyle 7 | import com.sasuke.launcheroneplus.util.Constants 8 | import com.sasuke.launcheroneplus.util.SharedPreferenceUtil 9 | import kotlinx.coroutines.Dispatchers 10 | import kotlinx.coroutines.launch 11 | import kotlinx.coroutines.withContext 12 | import javax.inject.Inject 13 | 14 | class AppDrawerActivityViewModel @Inject constructor( 15 | private val sharedPreferenceUtil: SharedPreferenceUtil, 16 | private val gson: Gson 17 | ) : 18 | ViewModel() { 19 | 20 | fun setFastScrollState(isEnabled: Boolean) { 21 | viewModelScope.launch { 22 | withContext(Dispatchers.IO) { 23 | sharedPreferenceUtil.getSettingPreference()?.let { 24 | it.isFastScrollEnabled = isEnabled 25 | sharedPreferenceUtil.putString(Constants.PREFERENCES, gson.toJson(it)) 26 | } 27 | } 28 | } 29 | } 30 | 31 | fun setDrawerStyle(style: String) { 32 | var indicator = DrawerStyle.VERTICAL 33 | when (style) { 34 | DrawerStyle.VERTICAL.name -> indicator = DrawerStyle.VERTICAL 35 | DrawerStyle.LIST.name -> indicator = DrawerStyle.LIST 36 | } 37 | viewModelScope.launch { 38 | withContext(Dispatchers.IO) { 39 | sharedPreferenceUtil.getSettingPreference()?.let { 40 | it.drawerStyle = indicator 41 | sharedPreferenceUtil.putString(Constants.PREFERENCES, gson.toJson(it)) 42 | } 43 | } 44 | } 45 | } 46 | 47 | fun setPrimaryColor(color: Int) { 48 | viewModelScope.launch { 49 | withContext(Dispatchers.IO) { 50 | sharedPreferenceUtil.getSettingPreference()?.let { 51 | it.primaryColor = color 52 | sharedPreferenceUtil.putString(Constants.PREFERENCES, gson.toJson(it)) 53 | } 54 | } 55 | } 56 | } 57 | 58 | fun setBackgroundColor(color: Int) { 59 | viewModelScope.launch { 60 | withContext(Dispatchers.IO) { 61 | sharedPreferenceUtil.getSettingPreference()?.let { 62 | it.backgroundColor = color 63 | sharedPreferenceUtil.putString(Constants.PREFERENCES, gson.toJson(it)) 64 | } 65 | } 66 | } 67 | } 68 | 69 | fun setBackgroundTransparency(transparency: Int) { 70 | viewModelScope.launch { 71 | withContext(Dispatchers.IO) { 72 | sharedPreferenceUtil.getSettingPreference()?.let { 73 | it.backgroundColorAlpha = 100 - transparency 74 | sharedPreferenceUtil.putString(Constants.PREFERENCES, gson.toJson(it)) 75 | } 76 | } 77 | } 78 | } 79 | } --------------------------------------------------------------------------------