├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── zhou │ │ └── app │ │ └── mywallpapers │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── primary_1.jpg │ ├── ic_add-web.png │ ├── ic_done-web.png │ ├── kotlin │ │ └── zhou │ │ │ └── app │ │ │ └── mywallpapers │ │ │ ├── App.kt │ │ │ ├── MainActivity.kt │ │ │ ├── common │ │ │ └── Config.kt │ │ │ ├── model │ │ │ └── Model.kt │ │ │ ├── persistence │ │ │ └── DatabaseManager.kt │ │ │ ├── ui │ │ │ ├── activity │ │ │ │ └── WallpaperDisplayActivity.kt │ │ │ ├── adapter │ │ │ │ └── WallpapersAdapter.kt │ │ │ ├── dialog │ │ │ │ └── WallpaperDetailDialog.kt │ │ │ ├── fragment │ │ │ │ └── WallpaperDisplayFragment.kt │ │ │ └── widget │ │ │ │ ├── AlphaDisableableButton.kt │ │ │ │ └── CropImageView.kt │ │ │ └── util │ │ │ ├── IOKit.kt │ │ │ ├── Interfaces.kt │ │ │ ├── PrefecenKit.kt │ │ │ ├── UriKit.kt │ │ │ └── Utils.kt │ └── res │ │ ├── drawable-hdpi │ │ ├── ic_add.png │ │ ├── ic_done.png │ │ ├── ic_file_cloud_off.png │ │ ├── ic_image_filter_hdr.png │ │ └── ic_select.png │ │ ├── drawable-mdpi │ │ ├── ic_add.png │ │ ├── ic_done.png │ │ ├── ic_file_cloud_off.png │ │ ├── ic_image_filter_hdr.png │ │ └── ic_select.png │ │ ├── drawable-xhdpi │ │ ├── ic_add.png │ │ ├── ic_done.png │ │ ├── ic_file_cloud_off.png │ │ ├── ic_image_filter_hdr.png │ │ └── ic_select.png │ │ ├── drawable-xxhdpi │ │ ├── ic_add.png │ │ ├── ic_done.png │ │ ├── ic_file_cloud_off.png │ │ ├── ic_image_filter_hdr.png │ │ └── ic_select.png │ │ ├── drawable-xxxhdpi │ │ ├── ic_add.png │ │ ├── ic_done.png │ │ ├── ic_file_cloud_off.png │ │ ├── ic_image_filter_hdr.png │ │ └── ic_select.png │ │ ├── drawable │ │ ├── background.jpg │ │ ├── error.xml │ │ ├── placeholder.xml │ │ ├── ripple_effect.xml │ │ ├── shadow.xml │ │ └── shadow_top.xml │ │ ├── layout │ │ ├── activity_display.xml │ │ ├── activity_main.xml │ │ ├── dialog_detail.xml │ │ ├── fragment_display.xml │ │ ├── item_add.xml │ │ └── item_image.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── zhou │ └── app │ └── mywallpapers │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image ├── image_1.jpg ├── image_2.jpg ├── image_3.jpg └── image_4.jpg └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | *.class 4 | 5 | # Mobile Tools for Java (J2ME) 6 | .mtj.tmp/ 7 | 8 | # Package Files # 9 | *.jar 10 | *.war 11 | *.ear 12 | 13 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 14 | hs_err_pid* 15 | ### JetBrains template 16 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 17 | 18 | *.iml 19 | 20 | ## Directory-based project format: 21 | .idea/ 22 | # if you remove the above rule, at least ignore the following: 23 | 24 | # User-specific stuff: 25 | # .idea/workspace.xml 26 | # .idea/tasks.xml 27 | # .idea/dictionaries 28 | 29 | # Sensitive or high-churn files: 30 | # .idea/dataSources.ids 31 | # .idea/dataSources.xml 32 | # .idea/sqlDataSources.xml 33 | # .idea/dynamic.xml 34 | # .idea/uiDesigner.xml 35 | 36 | # Gradle: 37 | # .idea/gradle.xml 38 | # .idea/libraries 39 | 40 | # Mongo Explorer plugin: 41 | # .idea/mongoSettings.xml 42 | 43 | ## File-based project format: 44 | *.ipr 45 | *.iws 46 | 47 | ## Plugin-specific files: 48 | 49 | # IntelliJ 50 | /out/ 51 | 52 | # mpeltonen/sbt-idea plugin 53 | .idea_modules/ 54 | 55 | # JIRA plugin 56 | atlassian-ide-plugin.xml 57 | 58 | # Crashlytics plugin (for Android Studio and IntelliJ) 59 | com_crashlytics_export_strings.xml 60 | crashlytics.properties 61 | crashlytics-build.properties 62 | ### NetBeans template 63 | nbproject/private/ 64 | build/ 65 | nbbuild/ 66 | dist/ 67 | nbdist/ 68 | nbactions.xml 69 | nb-configuration.xml 70 | .nb-gradle/ 71 | ### Eclipse template 72 | *.pydevproject 73 | .metadata 74 | .gradle 75 | bin/ 76 | tmp/ 77 | *.tmp 78 | *.bak 79 | *.swp 80 | *~.nib 81 | local.properties 82 | .settings/ 83 | .loadpath 84 | 85 | # Eclipse Core 86 | .project 87 | 88 | # External tool builders 89 | .externalToolBuilders/ 90 | 91 | # Locally stored "Eclipse launch configurations" 92 | *.launch 93 | 94 | # CDT-specific 95 | .cproject 96 | 97 | # JDT-specific (Eclipse Java Development Tools) 98 | .classpath 99 | 100 | # Java annotation processor (APT) 101 | .factorypath 102 | 103 | # PDT-specific 104 | .buildpath 105 | 106 | # sbteclipse plugin 107 | .target 108 | 109 | # TeXlipse plugin 110 | .texlipse 111 | ### JDeveloper template 112 | # default application storage directory used by the IDE Performance Cache feature 113 | .data/ 114 | 115 | # used for ADF styles caching 116 | temp/ 117 | 118 | # default output directories 119 | classes/ 120 | deploy/ 121 | javadoc/ 122 | 123 | # lock file, a part of Oracle Credential Store Framework 124 | cwallet.sso.lck### OSX template 125 | .DS_Store 126 | .AppleDouble 127 | .LSOverride 128 | 129 | # Icon must end with two \r 130 | Icon 131 | 132 | # Thumbnails 133 | ._* 134 | 135 | # Files that might appear in the root of a volume 136 | .DocumentRevisions-V100 137 | .fseventsd 138 | .Spotlight-V100 139 | .TemporaryItems 140 | .Trashes 141 | .VolumeIcon.icns 142 | 143 | # Directories potentially created on remote AFP share 144 | .AppleDB 145 | .AppleDesktop 146 | Network Trash Folder 147 | Temporary Items 148 | .apdisk 149 | ### Windows template 150 | # Windows image file caches 151 | Thumbs.db 152 | ehthumbs.db 153 | 154 | # Folder config file 155 | Desktop.ini 156 | 157 | # Recycle Bin used on file shares 158 | $RECYCLE.BIN/ 159 | 160 | # Windows Installer files 161 | *.cab 162 | *.msi 163 | *.msm 164 | *.msp 165 | 166 | # Windows shortcuts 167 | *.lnk 168 | ### Linux template 169 | *~ 170 | 171 | # KDE directory preferences 172 | .directory 173 | 174 | # Linux trash folder which might appear on any partition or disk 175 | .Trash-* 176 | ### Gradle template 177 | .gradle 178 | build/ 179 | 180 | # Ignore Gradle GUI config 181 | gradle-app.setting 182 | 183 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 184 | !gradle-wrapper.jar 185 | ### Android template 186 | # Built application files 187 | *.apk 188 | *.ap_ 189 | 190 | # Files for the Dalvik VM 191 | *.dex 192 | 193 | # Java class files 194 | *.class 195 | 196 | # Generated files 197 | bin/ 198 | gen/ 199 | 200 | # Gradle files 201 | .gradle/ 202 | build/ 203 | 204 | # Local configuration file (sdk path, etc) 205 | local.properties 206 | 207 | # Proguard folder generated by Eclipse 208 | proguard/ 209 | 210 | # Log Files 211 | *.log 212 | 213 | # Android Studio Navigation editor temp files 214 | .navigation/ 215 | 216 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | MyWallpaper -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WallpaperStore 2 | 3 | > 壁纸库 4 | 5 | 完全使用Kotlin开发的壁纸库,将喜欢的壁纸都收藏起来吧 6 | 7 | ### Apk 8 | 9 | [这里下载](https://www.pgyer.com/wallpaper-store) 10 | 11 | ### 截图 12 | 13 | ![截图1](image/image_1.jpg) 14 | ![截图2](image/image_2.jpg) 15 | ![截图3](image/image_3.jpg) 16 | ![截图4](image/image_4.jpg) 17 | 18 | _by zzhoujay_ -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 23 7 | buildToolsVersion "23.0.2" 8 | 9 | defaultConfig { 10 | applicationId "zhou.app.mywallpapers" 11 | minSdkVersion 15 12 | targetSdkVersion 23 13 | versionCode 2 14 | versionName "1.0.1" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | sourceSets { 23 | main.java.srcDirs += 'src/main/kotlin' 24 | } 25 | } 26 | 27 | dependencies { 28 | compile fileTree(include: ['*.jar'], dir: 'libs') 29 | testCompile 'junit:junit:4.12' 30 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 31 | compile "org.jetbrains.anko:anko-common:$anko_version" 32 | compile "org.jetbrains.anko:anko-sqlite:$anko_version" 33 | compile "org.jetbrains.anko:anko-sdk23:$anko_version" 34 | compile 'com.github.bumptech.glide:glide:3.7.0' 35 | compile 'com.squareup:otto:1.3.8' 36 | compile 'com.android.support:appcompat-v7:23.2.0' 37 | compile 'com.android.support:recyclerview-v7:23.2.0' 38 | compile 'com.karumi:dexter:2.2.1' 39 | } 40 | 41 | buildscript { 42 | ext.kotlin_version = '1.0.0' 43 | ext.anko_version = '0.8.2' 44 | repositories { 45 | mavenCentral() 46 | } 47 | dependencies { 48 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 49 | } 50 | } 51 | 52 | repositories { 53 | mavenCentral() 54 | } 55 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/zhou/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/zhou/app/mywallpapers/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/assets/primary_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/assets/primary_1.jpg -------------------------------------------------------------------------------- /app/src/main/ic_add-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/ic_add-web.png -------------------------------------------------------------------------------- /app/src/main/ic_done-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/ic_done-web.png -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/App.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers 2 | 3 | import android.app.Application 4 | import com.karumi.dexter.Dexter 5 | import com.squareup.otto.Bus 6 | import zhou.app.mywallpapers.common.Config 7 | import zhou.app.mywallpapers.model.Wallpaper 8 | import zhou.app.mywallpapers.persistence.DatabaseManager 9 | import zhou.app.mywallpapers.util.getBoolean 10 | import zhou.app.mywallpapers.util.setBoolean 11 | import kotlin.properties.Delegates 12 | 13 | /** 14 | * Created by zhou on 16-2-20. 15 | * Application 16 | */ 17 | class App : Application() { 18 | 19 | companion object { 20 | var instance: App by Delegates.notNull() 21 | } 22 | 23 | val bus: Bus = Bus() 24 | 25 | 26 | override fun onCreate() { 27 | super.onCreate() 28 | instance = this 29 | Dexter.initialize(this) 30 | if (getBoolean(this, Config.Tag.initStart, true)) { 31 | // DatabaseManager.instance.insert(Wallpaper("", "file:///android_asset/primary_3.jpg", true)) 32 | // DatabaseManager.instance.insert(Wallpaper("", "file:///android_asset/primary_2.jpg", true)) 33 | DatabaseManager.instance.insert(Wallpaper("放风筝的女孩", "file:///android_asset/primary_1.jpg", true)) 34 | } 35 | setBoolean(this, Config.Tag.initStart, false) 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import kotlinx.android.synthetic.main.activity_main.* 6 | import org.jetbrains.anko.startActivity 7 | import zhou.app.mywallpapers.ui.activity.WallpaperDisplayActivity 8 | 9 | class MainActivity : AppCompatActivity() { 10 | 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | setContentView(R.layout.activity_main) 14 | 15 | button.setOnClickListener { 16 | startActivity() 17 | } 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/common/Config.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.common 2 | 3 | /** 4 | * Created by zhou on 16-2-25. 5 | * 一些配置信息、常量等 6 | */ 7 | 8 | object Config { 9 | 10 | object Database { 11 | val DATABASE_NAME = "wallpapers.db" 12 | val TABLE_NAME = "wallpaper" 13 | val ID = "id" 14 | val TITLE = "title" 15 | val URL = "url" 16 | val DATE = "date" 17 | val PROTECT = "protect" 18 | val DATABASE_VERSION = 1 19 | } 20 | 21 | object Action { 22 | const val preview_wallpaper = 0x1234 23 | const val set_wallpaper = 0x1235 24 | const val cache_dialog = 0x432 25 | const val reload_list = 0x134 26 | const val notifier_permission_ready = 0x666 27 | } 28 | 29 | object Tag { 30 | const val wallpaper = "wallpaper" 31 | const val initStart = "initStart" 32 | const val asset_prefix = "file:///android_asset/" 33 | } 34 | 35 | object Flag { 36 | const val result_select_image = 18 37 | const val result_pick_image = 0x123 38 | const val permission_flag = 5 39 | } 40 | 41 | object Id { 42 | const val menu_edit = 0x123 43 | const val menu_delete = 0x234 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/model/Model.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.model 2 | 3 | import android.os.Parcel 4 | import android.os.Parcelable 5 | 6 | import java.util.* 7 | 8 | /** 9 | * Created by zhou on 16-2-20. 10 | * 壁纸的模型类 11 | */ 12 | 13 | data class Wallpaper(var title: String = "", var url: String, var protect: Boolean = false, var date: Date = Date()) : Parcelable { 14 | var id: Int? = null 15 | 16 | constructor(id: Int, title: String = "", url: String, protect: Boolean, date: Date) : this(title, url, protect, date) { 17 | this.id = id 18 | } 19 | 20 | constructor(source: Parcel) : this(source.readString(), source.readString(), 1.toByte().equals(source.readByte()), source.readSerializable() as Date) 21 | 22 | override fun describeContents(): Int { 23 | return 0 24 | } 25 | 26 | override fun writeToParcel(dest: Parcel?, flags: Int) { 27 | dest?.writeString(title) 28 | dest?.writeString(url) 29 | dest?.writeByte((if (protect) 1 else 0).toByte()) 30 | dest?.writeSerializable(date) 31 | } 32 | 33 | companion object { 34 | @JvmField final val CREATOR: Parcelable.Creator = object : Parcelable.Creator { 35 | override fun createFromParcel(source: Parcel): Wallpaper { 36 | return Wallpaper(source) 37 | } 38 | 39 | override fun newArray(size: Int): Array { 40 | return arrayOfNulls(size) 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/persistence/DatabaseManager.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.persistence 2 | 3 | import android.database.sqlite.SQLiteDatabase 4 | import android.util.Log 5 | import org.jetbrains.anko.db.* 6 | import zhou.app.mywallpapers.App 7 | import zhou.app.mywallpapers.common.Config 8 | import zhou.app.mywallpapers.model.Wallpaper 9 | import java.util.* 10 | 11 | /** 12 | * Created by zhou on 16-2-21. 13 | * 数据库操作工具类 14 | */ 15 | 16 | class DatabaseManager : ManagedSQLiteOpenHelper(App.instance, Config.Database.DATABASE_NAME, version = Config.Database.DATABASE_VERSION) { 17 | 18 | override fun onCreate(sqLiteDatabase: SQLiteDatabase?) { 19 | sqLiteDatabase?.createTable(Config.Database.TABLE_NAME, true, 20 | Config.Database.ID to INTEGER + PRIMARY_KEY + AUTOINCREMENT, 21 | Config.Database.TITLE to TEXT, 22 | Config.Database.URL to TEXT, 23 | Config.Database.PROTECT to INTEGER, 24 | Config.Database.DATE to INTEGER) 25 | 26 | } 27 | 28 | override fun onUpgrade(sqLiteDatabase: SQLiteDatabase?, p1: Int, p2: Int) { 29 | sqLiteDatabase?.dropTable(Config.Database.TABLE_NAME, true) 30 | onCreate(sqLiteDatabase) 31 | } 32 | 33 | /** 34 | * 插入数据 35 | */ 36 | fun insert(wallpaper: Wallpaper): Boolean { 37 | return try { 38 | use { 39 | insert(Config.Database.TABLE_NAME, 40 | Config.Database.TITLE to wallpaper.title, 41 | Config.Database.URL to wallpaper.url, 42 | Config.Database.PROTECT to wallpaper.protect, 43 | Config.Database.DATE to wallpaper.date.time) 44 | } 45 | true 46 | } catch(e: Exception) { 47 | Log.d(TAG, "insert") 48 | false 49 | } 50 | } 51 | 52 | /** 53 | * 删除 54 | */ 55 | fun delete(id: Int?): Boolean { 56 | if (id == null) { 57 | return false 58 | } 59 | return try { 60 | use { 61 | delete(Config.Database.TABLE_NAME, "${Config.Database.ID}={${Config.Database.ID}}", Config.Database.ID to id) 62 | } 63 | true 64 | } catch(e: Exception) { 65 | Log.d(TAG, "delete", e) 66 | false 67 | } 68 | } 69 | 70 | /** 71 | * 更新Title和Url 72 | */ 73 | fun update(wallpaper: Wallpaper) { 74 | use { 75 | update(Config.Database.TABLE_NAME, 76 | Config.Database.TITLE to wallpaper.title, 77 | Config.Database.URL to wallpaper.url).where("${Config.Database.ID}={${Config.Database.ID}}", Config.Database.ID to wallpaper.id!!).exec() 78 | } 79 | } 80 | 81 | /** 82 | * 查询所有的数据 83 | */ 84 | fun select(): ArrayList { 85 | var wallpapers: ArrayList? = null 86 | use { 87 | select(Config.Database.TABLE_NAME).orderBy(Config.Database.DATE, SqlOrderDirection.DESC).exec { 88 | if (count <= 0) { 89 | return@exec 90 | } 91 | wallpapers = ArrayList(count) 92 | moveToFirst() 93 | if (id_index == null) { 94 | id_index = getColumnIndex(Config.Database.ID) 95 | title_index = getColumnIndex(Config.Database.TITLE) 96 | url_index = getColumnIndex(Config.Database.URL) 97 | date_index = getColumnIndex(Config.Database.DATE) 98 | protect_index = getColumnIndex(Config.Database.PROTECT) 99 | } 100 | do { 101 | val wallpaper = Wallpaper(getInt(id_index!!), getString(title_index!!), getString(url_index!!), getInt(protect_index!!) != 0, Date(getLong(date_index!!))) 102 | wallpapers!!.add(wallpaper) 103 | } while (moveToNext()) 104 | } 105 | } 106 | return wallpapers ?: ArrayList(0) 107 | } 108 | 109 | companion object { 110 | var id_index: Int? = null 111 | var title_index: Int? = null 112 | var url_index: Int? = null 113 | var date_index: Int? = null 114 | var protect_index: Int? = null 115 | 116 | const val TAG = "DatabaseManager" 117 | 118 | val instance: DatabaseManager by lazy { 119 | DatabaseManager() 120 | } 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/ui/activity/WallpaperDisplayActivity.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.ui.activity 2 | 3 | import android.Manifest 4 | import android.app.WallpaperManager 5 | import android.content.Intent 6 | import android.os.Bundle 7 | import android.support.v7.app.AppCompatActivity 8 | import com.bumptech.glide.Glide 9 | import com.karumi.dexter.Dexter 10 | import com.karumi.dexter.PermissionToken 11 | import com.karumi.dexter.listener.PermissionDeniedResponse 12 | import com.karumi.dexter.listener.PermissionGrantedResponse 13 | import com.karumi.dexter.listener.PermissionRequest 14 | import com.karumi.dexter.listener.single.PermissionListener 15 | import com.squareup.otto.Subscribe 16 | import kotlinx.android.synthetic.main.activity_display.* 17 | import org.jetbrains.anko.alert 18 | import org.jetbrains.anko.toast 19 | import zhou.app.mywallpapers.App 20 | import zhou.app.mywallpapers.R 21 | import zhou.app.mywallpapers.common.Config 22 | import zhou.app.mywallpapers.model.Wallpaper 23 | import zhou.app.mywallpapers.ui.dialog.WallpaperDetailDialog 24 | import zhou.app.mywallpapers.ui.fragment.WallpaperDisplayFragment 25 | import zhou.app.mywallpapers.util.Callback0 26 | import zhou.app.mywallpapers.util.Event 27 | import zhou.app.mywallpapers.util.getImagePathFromUri 28 | import zhou.app.mywallpapers.util.loadWallpaperInputStream 29 | 30 | /** 31 | * Created by zhou on 16-2-21. 32 | * 壁纸选择Activity 33 | */ 34 | class WallpaperDisplayActivity : AppCompatActivity() { 35 | 36 | private var wallpaperFragment: WallpaperDisplayFragment? = null 37 | private var currWallpaper: Wallpaper? = null 38 | 39 | private var wallpaperDetailDialog: WallpaperDetailDialog? = null 40 | 41 | 42 | override fun onCreate(savedInstanceState: Bundle?) { 43 | super.onCreate(savedInstanceState) 44 | setContentView(R.layout.activity_display) 45 | 46 | wallpaper_preview.setImageDrawable(WallpaperManager.getInstance(applicationContext).drawable) 47 | 48 | wallpaperFragment = WallpaperDisplayFragment.newInstance() 49 | 50 | supportFragmentManager.beginTransaction().add(R.id.container, wallpaperFragment).commit() 51 | 52 | wallpaper_preview.onTapCallback = object : Callback0 { 53 | override fun call() { 54 | if (currWallpaper != null) { 55 | wallpaperFragment?.optionBarVisible = !(wallpaperFragment?.optionBarVisible ?: false) 56 | } 57 | } 58 | } 59 | 60 | checkPermission() 61 | } 62 | 63 | fun checkPermission() { 64 | 65 | Dexter.checkPermission(object : PermissionListener { 66 | override fun onPermissionGranted(p0: PermissionGrantedResponse?) { 67 | wallpaperFragment?.onPermissionReady() 68 | } 69 | 70 | override fun onPermissionRationaleShouldBeShown(p0: PermissionRequest?, p1: PermissionToken?) { 71 | p1?.continuePermissionRequest() 72 | } 73 | 74 | override fun onPermissionDenied(p0: PermissionDeniedResponse?) { 75 | alert(R.string.permission_message, R.string.permission_title, { 76 | builder.setPositiveButton(R.string.permission_positive, { dialog, which -> 77 | checkPermission() 78 | }).setNegativeButton(R.string.permission_negative, { dialog, which -> 79 | finish() 80 | }) 81 | }).show() 82 | 83 | } 84 | 85 | }, Manifest.permission.WRITE_EXTERNAL_STORAGE) 86 | 87 | } 88 | 89 | override fun onResume() { 90 | super.onResume() 91 | App.instance.bus.register(this) 92 | } 93 | 94 | 95 | override fun onPause() { 96 | super.onPause() 97 | App.instance.bus.unregister(this) 98 | } 99 | 100 | @Subscribe 101 | fun handleEvent(event: Event) { 102 | when (event.code) { 103 | Config.Action.cache_dialog -> { 104 | if (event.value is WallpaperDetailDialog) { 105 | wallpaperDetailDialog = event.value 106 | } 107 | } 108 | Config.Action.preview_wallpaper -> { 109 | if (event.value != null && event.value is Wallpaper) { 110 | currWallpaper = event.value 111 | Glide.with(this).load(event.value.url) 112 | .error(R.drawable.error) 113 | .placeholder(R.drawable.placeholder) 114 | .crossFade() 115 | .into(wallpaper_preview) 116 | } 117 | wallpaperFragment?.topBarEnable = currWallpaper != null 118 | } 119 | Config.Action.set_wallpaper -> { 120 | if (currWallpaper != null) { 121 | val wallpaperInputStream = loadWallpaperInputStream(currWallpaper!!.url) 122 | if (wallpaperInputStream != null) { 123 | val wm = WallpaperManager.getInstance(applicationContext) 124 | wm.setStream(wallpaperInputStream) 125 | toast("壁纸设置成功") 126 | return 127 | } 128 | } 129 | toast("设置失败") 130 | } 131 | } 132 | } 133 | 134 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 135 | super.onActivityResult(requestCode, resultCode, data) 136 | if (requestCode == Config.Flag.result_pick_image && resultCode == RESULT_OK) { 137 | val path = getImagePathFromUri(applicationContext, data?.data) 138 | if (path == null) { 139 | toast("文件无效") 140 | } else { 141 | val wallpaper = Wallpaper(url = path) 142 | wallpaperFragment?.reloadWallpaper(wallpaper) 143 | } 144 | } else if (requestCode == Config.Flag.result_select_image && resultCode == RESULT_OK) { 145 | val path = getImagePathFromUri(applicationContext, data?.data) 146 | if (path == null) { 147 | toast("文件无效") 148 | } else { 149 | wallpaperDetailDialog?.imagePath = path 150 | println("path:$path") 151 | } 152 | } 153 | } 154 | 155 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/ui/adapter/WallpapersAdapter.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.ui.adapter 2 | 3 | import android.content.Context 4 | import android.support.v7.widget.RecyclerView 5 | import android.text.TextUtils 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import android.widget.ImageView 10 | import android.widget.TextView 11 | import com.bumptech.glide.Glide 12 | import org.jetbrains.anko.UI 13 | import kotlinx.android.synthetic.main.item_add.view.* 14 | import kotlinx.android.synthetic.main.item_image.view.* 15 | import zhou.app.mywallpapers.R 16 | import zhou.app.mywallpapers.model.Wallpaper 17 | import zhou.app.mywallpapers.util.Callback 18 | import zhou.app.mywallpapers.util.Callback3 19 | import zhou.app.mywallpapers.util.OnClickCallback 20 | 21 | /** 22 | * Created by zhou on 16-2-20. 23 | * 壁纸列表适配器 24 | */ 25 | class WallpapersAdapter(ctx: Context? = null, wps: List? = null) : RecyclerView.Adapter() { 26 | 27 | val functionalCount = 1 28 | 29 | var select = -1 30 | var selectWallpaper: Wallpaper? = null 31 | var itemClickCallback: Callback? = null 32 | var addClickCallback: Callback? = null 33 | var itemLongClickCallback: Callback3? = null 34 | var context: Context? = null 35 | var wallpapers: List? = null 36 | set(value) { 37 | field = value 38 | value?.forEachIndexed { index, wallpaper -> 39 | if (wallpaper.equals(selectWallpaper)) { 40 | select = index + functionalCount 41 | selectWallpaper = wallpaper 42 | return 43 | } 44 | } 45 | select = -1 46 | selectWallpaper = null 47 | } 48 | 49 | init { 50 | this.context = ctx 51 | this.wallpapers = wps 52 | } 53 | 54 | private val onAddCallback = object : OnClickCallback { 55 | override fun onClick(view: View, position: Int) { 56 | addClickCallback?.call() 57 | } 58 | } 59 | private val onItemClickCallback = object : OnClickCallback { 60 | override fun onClick(view: View, position: Int) { 61 | val w = wallpapers!![position - functionalCount] 62 | if (position >= functionalCount) { 63 | notifyItemChanged(select) 64 | notifyItemChanged(position) 65 | select = position 66 | selectWallpaper = w 67 | } 68 | itemClickCallback?.call(w) 69 | } 70 | } 71 | 72 | private val onItemLongClickCallback = object : OnClickCallback { 73 | override fun onClick(view: View, position: Int) { 74 | itemLongClickCallback?.call(view, wallpapers!![position - 1], position) 75 | } 76 | } 77 | 78 | override fun onBindViewHolder(holder: BaseHolder?, position: Int) { 79 | if (holder is WallpaperHolder) { 80 | val wallpaper = wallpapers!![position - 1] 81 | 82 | if (TextUtils.isEmpty(wallpaper.title)) { 83 | holder.title.visibility = View.INVISIBLE 84 | } else { 85 | holder.title.visibility = View.VISIBLE 86 | holder.title.text = wallpaper.title 87 | } 88 | if (select < 0) { 89 | holder.checked = false 90 | } else { 91 | holder.checked = position == select 92 | } 93 | Glide.with(context) 94 | .load(wallpaper.url) 95 | .error(R.drawable.error) 96 | .placeholder(R.drawable.placeholder) 97 | .crossFade() 98 | .into(holder.wallpaper) 99 | } 100 | } 101 | 102 | override fun getItemCount(): Int { 103 | return (wallpapers?.size ?: 0) + functionalCount 104 | } 105 | 106 | override fun onCreateViewHolder(p0: ViewGroup?, p1: Int): BaseHolder? { 107 | if (context == null) { 108 | context = p0!!.context 109 | } 110 | var holder: BaseHolder 111 | if (p1 == TYPE_ADD) { 112 | holder = FunctionalHolder(LayoutInflater.from(context).inflate(R.layout.item_add, null)) 113 | holder.clickCallback = onAddCallback 114 | } else { 115 | holder = WallpaperHolder(LayoutInflater.from(context).inflate(R.layout.item_image, null)) 116 | holder.clickCallback = onItemClickCallback 117 | holder.longClickCallback = onItemLongClickCallback 118 | } 119 | return holder 120 | } 121 | 122 | override fun getItemViewType(position: Int): Int { 123 | if (position == 0) { 124 | return TYPE_ADD 125 | } else { 126 | return TYPE_ITEM 127 | } 128 | } 129 | 130 | open class BaseHolder(val root: View) : RecyclerView.ViewHolder(root) { 131 | 132 | var clickCallback: OnClickCallback? = null 133 | var longClickCallback: OnClickCallback? = null 134 | 135 | init { 136 | root.setOnClickListener { 137 | clickCallback?.onClick(root, adapterPosition) 138 | } 139 | root.setOnLongClickListener { 140 | longClickCallback?.onClick(root, adapterPosition) 141 | true 142 | } 143 | } 144 | } 145 | 146 | /** 147 | * 功能类Holder 148 | */ 149 | class FunctionalHolder(root: View) : BaseHolder(root) { 150 | 151 | val icon: ImageView 152 | val text: TextView 153 | 154 | init { 155 | icon = root.icon_add 156 | text = root.text 157 | } 158 | } 159 | 160 | /** 161 | * 壁纸缩略图Holder 162 | */ 163 | class WallpaperHolder(root: View) : BaseHolder(root) { 164 | 165 | val wallpaper: ImageView 166 | val title: TextView 167 | val icon: ImageView 168 | 169 | var checked = false 170 | set(value) { 171 | field = value 172 | if (value) { 173 | icon.visibility = View.VISIBLE 174 | } else { 175 | icon.visibility = View.GONE 176 | } 177 | } 178 | 179 | init { 180 | wallpaper = root.icon 181 | title = root.title 182 | icon = root.wallpaper_icon 183 | } 184 | 185 | } 186 | 187 | companion object { 188 | const val TYPE_ADD = 1 189 | const val TYPE_ITEM = 0 190 | } 191 | 192 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/ui/dialog/WallpaperDetailDialog.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.ui.dialog 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.os.Bundle 7 | import android.support.v4.app.DialogFragment 8 | import android.support.v7.app.AlertDialog 9 | import android.view.LayoutInflater 10 | import android.widget.ImageView 11 | import com.bumptech.glide.Glide 12 | import kotlinx.android.synthetic.main.dialog_detail.view.* 13 | import org.jetbrains.anko.async 14 | import org.jetbrains.anko.uiThread 15 | import zhou.app.mywallpapers.App 16 | import zhou.app.mywallpapers.R 17 | import zhou.app.mywallpapers.common.Config 18 | import zhou.app.mywallpapers.model.Wallpaper 19 | import zhou.app.mywallpapers.persistence.DatabaseManager 20 | import zhou.app.mywallpapers.ui.fragment.WallpaperDisplayFragment 21 | import zhou.app.mywallpapers.util.Event 22 | import zhou.app.mywallpapers.util.notice 23 | 24 | /** 25 | * Created by zhou on 16-2-23. 26 | * 显示壁纸详情得Dialog 27 | */ 28 | class WallpaperDetailDialog : DialogFragment() { 29 | 30 | companion object { 31 | 32 | fun newInstance(wallpaper: Wallpaper? = null): WallpaperDetailDialog { 33 | val f = WallpaperDetailDialog() 34 | if (wallpaper != null) { 35 | val b = Bundle() 36 | b.putParcelable(Config.Tag.wallpaper, wallpaper) 37 | f.arguments = b 38 | } 39 | return f 40 | } 41 | } 42 | 43 | var imagePath: String? = null 44 | set(value) { 45 | if (image != null && value != null) { 46 | image!!.postDelayed({ 47 | Glide.with(this) 48 | .load(value) 49 | .error(R.drawable.error) 50 | .placeholder(R.drawable.placeholder) 51 | .crossFade() 52 | .into(image) 53 | }, 500) 54 | } 55 | field = value 56 | } 57 | 58 | var image: ImageView? = null 59 | 60 | override fun onAttach(context: Context?) { 61 | super.onAttach(context) 62 | App.instance.bus.register(this) 63 | } 64 | 65 | override fun onDetach() { 66 | super.onDetach() 67 | App.instance.bus.unregister(this) 68 | } 69 | 70 | 71 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 72 | val builder = AlertDialog.Builder(context) 73 | 74 | val view = LayoutInflater.from(context).inflate(R.layout.dialog_detail, null) 75 | 76 | var wallpaper: Wallpaper? = null 77 | 78 | if (arguments.containsKey(Config.Tag.wallpaper)) { 79 | wallpaper = arguments.getParcelable(Config.Tag.wallpaper) 80 | } 81 | 82 | image = view.imageView 83 | 84 | view.editText.setText(wallpaper?.title ?: "") 85 | Glide.with(this).load(wallpaper?.url).into(view.imageView) 86 | 87 | view.imageView.setOnClickListener { 88 | val i = Intent(Intent.ACTION_GET_CONTENT) 89 | i.type = "image/*" 90 | activity.startActivityForResult(i, Config.Flag.result_select_image); 91 | } 92 | 93 | 94 | builder.setView(view).setPositiveButton("确定", { p0, p1 -> 95 | val title = view.editText.text.toString() 96 | if (wallpaper != null && (!wallpaper!!.title.equals(title) || (imagePath != null && !wallpaper!!.url.equals(imagePath)))) { 97 | wallpaper!!.title = title 98 | if (imagePath != null) { 99 | wallpaper!!.url = imagePath!! 100 | } 101 | async() { 102 | DatabaseManager.instance.update(wallpaper!!) 103 | uiThread { 104 | notice(Event(Config.Action.reload_list, null, this@WallpaperDetailDialog, WallpaperDisplayFragment::class.java)) 105 | dismiss() 106 | } 107 | } 108 | } 109 | }).setNegativeButton("取消", null) 110 | 111 | return builder.create() 112 | } 113 | 114 | 115 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/ui/fragment/WallpaperDisplayFragment.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.ui.fragment 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.support.v4.app.Fragment 6 | import android.support.v7.widget.LinearLayoutManager 7 | import android.support.v7.widget.PopupMenu 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.view.animation.* 12 | import com.squareup.otto.Subscribe 13 | import kotlinx.android.synthetic.main.fragment_display.* 14 | import org.jetbrains.anko.async 15 | import org.jetbrains.anko.enabled 16 | import org.jetbrains.anko.uiThread 17 | import zhou.app.mywallpapers.App 18 | import zhou.app.mywallpapers.R 19 | import zhou.app.mywallpapers.common.Config 20 | import zhou.app.mywallpapers.model.Wallpaper 21 | import zhou.app.mywallpapers.persistence.DatabaseManager 22 | import zhou.app.mywallpapers.ui.adapter.WallpapersAdapter 23 | import zhou.app.mywallpapers.ui.dialog.WallpaperDetailDialog 24 | import zhou.app.mywallpapers.util.* 25 | 26 | 27 | /** 28 | * Created by zhou on 16-2-21. 29 | * 壁纸展示的Fragment 30 | */ 31 | class WallpaperDisplayFragment : Fragment() { 32 | 33 | var adapter: WallpapersAdapter? = null 34 | var needToReload = false 35 | private set 36 | 37 | override fun onResume() { 38 | super.onResume() 39 | App.instance.bus.register(this) 40 | } 41 | 42 | override fun onPause() { 43 | super.onPause() 44 | App.instance.bus.unregister(this) 45 | } 46 | 47 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { 48 | return inflater!!.inflate(R.layout.fragment_display, container, false) 49 | } 50 | 51 | override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { 52 | super.onViewCreated(view, savedInstanceState) 53 | 54 | recyclerView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) 55 | if (adapter == null) { 56 | adapter = WallpapersAdapter(context) 57 | adapter!!.addClickCallback = object : Callback { 58 | override fun call(t: Wallpaper?) { 59 | val i = Intent(Intent.ACTION_GET_CONTENT) 60 | i.type = "image/*" 61 | activity.startActivityForResult(i, Config.Flag.result_pick_image); 62 | } 63 | } 64 | adapter!!.itemClickCallback = object : Callback { 65 | override fun call(t: Wallpaper?) { 66 | notice(Event(Config.Action.preview_wallpaper, t)) 67 | } 68 | } 69 | adapter!!.itemLongClickCallback = object : Callback3 { 70 | override fun call(t: View?, k: Wallpaper?, m: Int?) { 71 | val popMenu = PopupMenu(context, t) 72 | val menu = popMenu.menu 73 | menu.add(0, Config.Id.menu_edit, 0, "编辑") 74 | if (!k?.protect!!) { 75 | menu.add(0, Config.Id.menu_delete, 1, "删除") 76 | } 77 | popMenu.setOnMenuItemClickListener { 78 | when (it.itemId) { 79 | Config.Id.menu_edit -> { 80 | val d = WallpaperDetailDialog.newInstance(k) 81 | notice(Event(Config.Action.cache_dialog, d)) 82 | d.show(fragmentManager, "detail") 83 | } 84 | Config.Id.menu_delete -> { 85 | async() { 86 | if (DatabaseManager.instance.delete(k?.id)) { 87 | uiThread { 88 | reloadWallpaper() 89 | toast("删除成功") 90 | } 91 | } 92 | } 93 | } 94 | } 95 | true 96 | } 97 | popMenu.show() 98 | } 99 | } 100 | } 101 | 102 | topBar.setOnClickListener { 103 | notice(Event(Config.Action.set_wallpaper)) 104 | } 105 | 106 | recyclerView.adapter = adapter 107 | 108 | if (needToReload) { 109 | reloadWallpaper() 110 | } 111 | 112 | } 113 | 114 | fun reloadWallpaper(wallpaper: Wallpaper? = null) { 115 | async() { 116 | if (wallpaper != null) { 117 | DatabaseManager.instance.insert(wallpaper) 118 | } 119 | val wallpapers = DatabaseManager.instance.select() 120 | uiThread { 121 | adapter!!.wallpapers = wallpapers 122 | adapter!!.notifyDataSetChanged() 123 | } 124 | } 125 | } 126 | 127 | fun onPermissionReady() { 128 | if (adapter != null) { 129 | reloadWallpaper() 130 | } else { 131 | needToReload = true 132 | } 133 | } 134 | 135 | @Subscribe 136 | fun handleEvent(event: Event) { 137 | when (event.code) { 138 | Config.Action.reload_list -> { 139 | if (event.value is Wallpaper) { 140 | reloadWallpaper(event.value) 141 | } else { 142 | reloadWallpaper() 143 | } 144 | } 145 | } 146 | } 147 | 148 | companion object { 149 | 150 | fun newInstance(): WallpaperDisplayFragment { 151 | val f = WallpaperDisplayFragment() 152 | return f; 153 | } 154 | } 155 | 156 | fun generateAnimation(show: Boolean, top: Boolean): Animation { 157 | val fromY = if (top) -1f else 1f 158 | val fromA = if (show) 0f else 1f 159 | val toA = if (show) 1f else 0f 160 | val animationTranslate = TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, fromY, Animation.RELATIVE_TO_SELF, 0f) 161 | val animationAlpha = AlphaAnimation(fromA, toA) 162 | val animationSet = AnimationSet(true) 163 | animationSet.interpolator = AccelerateInterpolator() 164 | animationSet.duration = 200 165 | animationSet.addAnimation(animationTranslate) 166 | animationSet.addAnimation(animationAlpha) 167 | return animationSet 168 | } 169 | 170 | val showAnimationTopBar: Animation by lazy { 171 | generateAnimation(true, true) 172 | } 173 | val showAnimationWallpapers: Animation by lazy { 174 | generateAnimation(true, false) 175 | } 176 | 177 | var optionBarVisible: Boolean 178 | get() = wallpapers.visibility == View.VISIBLE 179 | set(value) { 180 | if (value) { 181 | topBarLayout.startAnimation(showAnimationTopBar) 182 | topBarLayout.visibility = View.VISIBLE 183 | wallpapers.startAnimation(showAnimationWallpapers) 184 | wallpapers.visibility = View.VISIBLE 185 | } else { 186 | topBarLayout.visibility = View.INVISIBLE 187 | wallpapers.visibility = View.INVISIBLE 188 | } 189 | } 190 | 191 | var topBarEnable: Boolean 192 | get() = topBar.enabled 193 | set(value) { 194 | topBar.enabled = value 195 | } 196 | 197 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/ui/widget/AlphaDisableableButton.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 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 zhou.app.mywallpapers.ui.widget 18 | 19 | import android.content.Context 20 | import android.util.AttributeSet 21 | import android.view.View 22 | import android.widget.Button 23 | 24 | /** 25 | * A Button which becomes translucent when it is disabled 26 | */ 27 | class AlphaDisableableButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : Button(context, attrs, defStyleAttr) { 28 | 29 | init { 30 | setLayerType(View.LAYER_TYPE_HARDWARE, null) 31 | } 32 | 33 | override fun setEnabled(enabled: Boolean) { 34 | super.setEnabled(enabled) 35 | if (enabled) { 36 | alpha = 1.0f 37 | } else { 38 | alpha = DISABLED_ALPHA_VALUE 39 | } 40 | } 41 | 42 | companion object { 43 | var DISABLED_ALPHA_VALUE = 0.4f 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/ui/widget/CropImageView.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.ui.widget 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.graphics.Bitmap 6 | import android.graphics.Canvas 7 | import android.graphics.Matrix 8 | import android.graphics.drawable.Drawable 9 | import android.os.Build 10 | import android.util.AttributeSet 11 | import android.view.GestureDetector 12 | import android.view.MotionEvent 13 | import android.widget.ImageView 14 | import zhou.app.mywallpapers.util.Callback 15 | import zhou.app.mywallpapers.util.Callback0 16 | 17 | /** 18 | * Created by zhou on 16-2-25. 19 | * 可拖动图片的ImageView 20 | */ 21 | class CropImageView : ImageView { 22 | 23 | 24 | constructor(context: Context) : super(context) { 25 | init() 26 | } 27 | 28 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { 29 | init() 30 | } 31 | 32 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { 33 | init() 34 | } 35 | 36 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 37 | constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { 38 | init() 39 | } 40 | 41 | val cropMatrix: Matrix by lazy { 42 | Matrix() 43 | } 44 | 45 | var offset = 0f 46 | var border = 0f 47 | var horizontal = true 48 | var hasMeasured = false 49 | var onTapCallback: Callback0? = null 50 | 51 | 52 | fun init() { 53 | super.setScaleType(ScaleType.MATRIX) 54 | } 55 | 56 | override fun setImageBitmap(bm: Bitmap?) { 57 | super.setImageBitmap(bm) 58 | resetMatrix() 59 | } 60 | 61 | override fun setImageResource(resId: Int) { 62 | super.setImageResource(resId) 63 | resetMatrix() 64 | } 65 | 66 | override fun setImageDrawable(drawable: Drawable?) { 67 | super.setImageDrawable(drawable) 68 | resetMatrix() 69 | } 70 | 71 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 72 | super.onMeasure(widthMeasureSpec, heightMeasureSpec) 73 | hasMeasured = true 74 | resetMatrix() 75 | } 76 | 77 | fun resetMatrix() { 78 | if (drawable == null || !hasMeasured) { 79 | return 80 | } 81 | val dwidth = drawable?.intrinsicWidth ?: 1 82 | val dheight = drawable?.intrinsicHeight ?: 1 83 | val vheight = height - paddingTop - paddingBottom 84 | val vwidth = width - paddingLeft - paddingRight 85 | val scale: Float 86 | var dx = 0f 87 | var dy = 0f 88 | 89 | if (dwidth * vheight > vwidth * dheight) { 90 | scale = vheight.toFloat() / dheight.toFloat() 91 | dx = (vwidth - dwidth * scale) * 0.5f 92 | horizontal = true 93 | border = ((dwidth * scale - vwidth) / 2) 94 | } else { 95 | scale = vwidth.toFloat() / dwidth.toFloat() 96 | dy = (vheight - dheight * scale) * 0.5f 97 | horizontal = false 98 | border = ((dheight * scale - vheight) / 2) 99 | } 100 | 101 | offset = 0f 102 | 103 | cropMatrix.setScale(scale, scale) 104 | cropMatrix.postTranslate(dx, dy) 105 | 106 | imageMatrix = cropMatrix 107 | 108 | invalidate() 109 | } 110 | 111 | 112 | val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() { 113 | override fun onDown(e: MotionEvent?): Boolean { 114 | return true 115 | } 116 | 117 | override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean { 118 | var d = if (horizontal) distanceX else distanceY 119 | var newMatrix = Matrix(cropMatrix) 120 | var reduce = d < 0 121 | var temp = d + offset 122 | 123 | if (reduce && (offset <= -border || temp <= -border)) { 124 | offset = -border 125 | } else if (!reduce && (offset >= border || temp >= border)) { 126 | offset = border 127 | } else { 128 | offset = temp 129 | } 130 | 131 | if (horizontal) { 132 | newMatrix.postTranslate(-offset, 0f) 133 | } else { 134 | newMatrix.postTranslate(0f, -offset) 135 | } 136 | imageMatrix = newMatrix 137 | invalidate() 138 | return true 139 | } 140 | 141 | override fun onSingleTapUp(e: MotionEvent?): Boolean { 142 | if (onTapCallback != null) { 143 | onTapCallback!!.call() 144 | return true 145 | } 146 | return false 147 | } 148 | 149 | }) 150 | 151 | override fun onTouchEvent(event: MotionEvent?): Boolean { 152 | return gestureDetector.onTouchEvent(event) 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/util/IOKit.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.util 2 | 3 | import zhou.app.mywallpapers.App 4 | import zhou.app.mywallpapers.common.Config 5 | import java.io.File 6 | import java.io.FileInputStream 7 | import java.io.InputStream 8 | 9 | /** 10 | * Created by zhou on 16-2-27. 11 | * IO工具 12 | */ 13 | 14 | fun loadWallpaperInputStream(path: String): InputStream? { 15 | if (path.startsWith(Config.Tag.asset_prefix)) { 16 | return App.instance.assets.open(path.replaceFirst(Config.Tag.asset_prefix, "")) 17 | } 18 | val file = File(path) 19 | if (file.exists()) { 20 | return FileInputStream(file) 21 | } 22 | return null 23 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/util/Interfaces.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.util 2 | 3 | import android.view.View 4 | 5 | /** 6 | * Created by zhou on 16-2-21. 7 | * 一些接口 8 | */ 9 | 10 | interface OnClickCallback { 11 | fun onClick(view: View, position: Int) 12 | } 13 | 14 | interface Callback0{ 15 | fun call() 16 | } 17 | 18 | interface Callback { 19 | fun call(t: T? = null) 20 | } 21 | 22 | interface Callback2 { 23 | fun call(t: T? = null, k: K? = null) 24 | } 25 | 26 | interface Callback3 { 27 | fun call(t: T? = null, k: K? = null, m: M? = null) 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/util/PrefecenKit.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.util 2 | 3 | import android.content.Context 4 | import org.jetbrains.anko.defaultSharedPreferences 5 | 6 | /** 7 | * Created by zhou on 16-2-28. 8 | */ 9 | 10 | fun getBoolean(ctx: Context, key: String, def: Boolean = false): Boolean { 11 | return ctx.defaultSharedPreferences.getBoolean(key, def) 12 | } 13 | 14 | fun setBoolean(ctx: Context, key: String, value: Boolean) { 15 | ctx.defaultSharedPreferences.edit().putBoolean(key, value).commit() 16 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/util/UriKit.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.util 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.database.Cursor 6 | import android.net.Uri 7 | import android.provider.MediaStore 8 | 9 | /** 10 | * Created by zhou on 16-2-23. 11 | * 从URI中获取真实路径的工具 12 | */ 13 | 14 | fun getImagePathFromUri(context: Context, fileUrl: Uri?): String? { 15 | var fileName: String? = null 16 | val filePathUri = fileUrl 17 | if (fileUrl != null) { 18 | if (fileUrl.scheme.compareTo("content") == 0) { 19 | // content://开头的uri 20 | val cursor = context.contentResolver.query(fileUrl, null, null, null, null) 21 | if (cursor != null && cursor.moveToFirst()) { 22 | val column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) 23 | fileName = cursor.getString(column_index) // 取出文件路径 24 | 25 | // Android 4.1 更改了SD的目录,sdcard映射到/storage/sdcard0 26 | if (!fileName!!.startsWith("/storage") && !fileName.startsWith("/mnt")) { 27 | // 检查是否有”/mnt“前缀 28 | fileName = "/mnt" + fileName 29 | } 30 | cursor.close() 31 | } 32 | } else if (fileUrl.scheme.compareTo("file") == 0) 33 | // file:///开头的uri 34 | { 35 | fileName = filePathUri.toString()// 替换file:// 36 | fileName = filePathUri.toString().replace("file://", "") 37 | @SuppressLint("SdCardPath") val index = fileName.indexOf("/sdcard") 38 | fileName = if (index == -1) fileName else fileName.substring(index) 39 | if (!fileName.startsWith("/mnt")) { 40 | // 加上"/mnt"头 41 | fileName += "/mnt" 42 | } 43 | } 44 | } 45 | return fileName 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/kotlin/zhou/app/mywallpapers/util/Utils.kt: -------------------------------------------------------------------------------- 1 | package zhou.app.mywallpapers.util 2 | 3 | import android.support.v4.app.Fragment 4 | import android.widget.Toast 5 | import zhou.app.mywallpapers.App 6 | 7 | /** 8 | * Created by zhou on 16-2-23. 9 | */ 10 | 11 | 12 | fun Fragment.toast(msg: CharSequence, time: Int = Toast.LENGTH_SHORT) { 13 | Toast.makeText(context, msg, time).show() 14 | } 15 | 16 | /** 17 | * 事件的封装类 18 | */ 19 | data class Event(val code: Int, val value: Any? = null, val from: Any? = null, val `to`: Any? = null) 20 | 21 | fun Any.notice(event: Event) { 22 | App.instance.bus.post(event) 23 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-hdpi/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-hdpi/ic_done.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_file_cloud_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-hdpi/ic_file_cloud_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_image_filter_hdr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-hdpi/ic_image_filter_hdr.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-hdpi/ic_select.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-mdpi/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-mdpi/ic_done.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_file_cloud_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-mdpi/ic_file_cloud_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_image_filter_hdr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-mdpi/ic_image_filter_hdr.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-mdpi/ic_select.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xhdpi/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xhdpi/ic_done.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_file_cloud_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xhdpi/ic_file_cloud_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_image_filter_hdr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xhdpi/ic_image_filter_hdr.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xhdpi/ic_select.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxhdpi/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxhdpi/ic_done.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_file_cloud_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxhdpi/ic_file_cloud_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_image_filter_hdr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxhdpi/ic_image_filter_hdr.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxhdpi/ic_select.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxxhdpi/ic_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxxhdpi/ic_done.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_file_cloud_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxxhdpi/ic_file_cloud_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_image_filter_hdr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxxhdpi/ic_image_filter_hdr.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable-xxxhdpi/ic_select.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzhoujay/WallpaperStore/b3085b0d0fe231b280fe45933535b77da756153c/app/src/main/res/drawable/background.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/placeholder.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ripple_effect.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shadow_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_display.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 |