From 792cc20cd1d6d8c9273a295da5fd856dee57ffa8 Mon Sep 17 00:00:00 2001 From: Giovanni Harting Date: Thu, 13 Aug 2015 03:27:24 +0200 Subject: [PATCH] Initial commit from non tracked working directory --- .gitignore | 140 ++++++ app/.gitignore | 1 + app/build.gradle | 45 ++ app/proguard-rules.txt | 17 + app/src/main/AndroidManifest.xml | 43 ++ .../idlegandalf/ledd/AssistantActivity.java | 73 ++++ .../com/idlegandalf/ledd/ColorActivity.java | 147 +++++++ .../idlegandalf/ledd/ColorApplication.java | 55 +++ .../com/idlegandalf/ledd/ColorService.java | 99 +++++ .../com/idlegandalf/ledd/DrawerFragment.java | 16 + .../ledd/ProgressBarActionBarActivity.java | 32 ++ .../idlegandalf/ledd/SettingsActivity.java | 17 + .../idlegandalf/ledd/SettingsFragment.java | 14 + .../ledd/components/Controller.java | 13 + .../com/idlegandalf/ledd/components/HSV.java | 12 + .../com/idlegandalf/ledd/components/Host.java | 27 ++ .../ledd/components/LEDDHelper.java | 68 +++ .../ledd/components/RGBStripe.java | 17 + .../ledd/components/StripeGroup.java | 62 +++ .../ledd/fragments/StepOneFragment.java | 233 ++++++++++ .../ledd/fragments/StepStripesFragment.java | 7 + .../ledd/fragments/WelcomeFragment.java | 218 ++++++++++ .../idlegandalf/ledd/utils/ColorPicker.java | 352 +++++++++++++++ .../ledd/utils/ColorPickerDialog.java | 54 +++ .../ledd/utils/ColorPickerPreference.java | 73 ++++ .../ledd/utils/MultiColorPicker.java | 401 ++++++++++++++++++ .../res/drawable-hdpi/drawer_shadow.9.png | Bin 0 -> 161 bytes .../res/drawable-hdpi/ic_action_settings.png | Bin 0 -> 953 bytes app/src/main/res/drawable-hdpi/ic_drawer.png | Bin 0 -> 2829 bytes .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 7366 bytes .../res/drawable-mdpi/drawer_shadow.9.png | Bin 0 -> 142 bytes .../res/drawable-mdpi/ic_action_settings.png | Bin 0 -> 594 bytes app/src/main/res/drawable-mdpi/ic_drawer.png | Bin 0 -> 2820 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 3876 bytes .../main/res/drawable-nodpi/ic_launcher.png | Bin 0 -> 9775 bytes .../res/drawable-xhdpi/drawer_shadow.9.png | Bin 0 -> 174 bytes .../res/drawable-xhdpi/ic_action_settings.png | Bin 0 -> 1231 bytes app/src/main/res/drawable-xhdpi/ic_drawer.png | Bin 0 -> 2836 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 11861 bytes .../res/drawable-xxhdpi/drawer_shadow.9.png | Bin 0 -> 208 bytes .../drawable-xxhdpi/ic_action_settings.png | Bin 0 -> 1863 bytes .../main/res/drawable-xxhdpi/ic_drawer.png | Bin 0 -> 202 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 21819 bytes app/src/main/res/drawable/dimme.xml | 6 + app/src/main/res/layout/act_demo.xml | 15 + app/src/main/res/layout/act_multi_picker.xml | 21 + app/src/main/res/layout/act_picker.xml | 21 + app/src/main/res/layout/act_pref.xml | 11 + app/src/main/res/layout/activity_asistent.xml | 4 + app/src/main/res/layout/activity_color.xml | 25 ++ app/src/main/res/layout/drawer_fragment.xml | 8 + app/src/main/res/layout/fragment_step1.xml | 84 ++++ app/src/main/res/layout/fragment_welcome.xml | 93 ++++ app/src/main/res/layout/host_row.xml | 20 + app/src/main/res/layout/progress.xml | 19 + app/src/main/res/menu/color.xml | 10 + app/src/main/res/menu/step1.xml | 4 + app/src/main/res/menu/welcome.xml | 3 + app/src/main/res/values-sw600dp/dimens.xml | 8 + .../main/res/values-sw720dp-land/dimens.xml | 9 + app/src/main/res/values-v11/styles.xml | 11 + app/src/main/res/values-v14/styles.xml | 12 + app/src/main/res/values-v21/styles.xml | 12 + app/src/main/res/values/dimens.xml | 7 + app/src/main/res/values/strings.xml | 9 + app/src/main/res/values/styles.xml | 20 + app/src/main/res/xml/settings.xml | 23 + build.gradle | 19 + gradle.properties | 18 + gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 +++++++ gradlew.bat | 90 ++++ lombok.config | 1 + settings.gradle | 1 + 74 files changed, 2990 insertions(+) create mode 100644 .gitignore create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.txt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/idlegandalf/ledd/AssistantActivity.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/ColorActivity.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/ColorApplication.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/ColorService.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/DrawerFragment.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/ProgressBarActionBarActivity.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/SettingsActivity.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/SettingsFragment.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/components/Controller.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/components/HSV.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/components/Host.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/components/LEDDHelper.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/components/RGBStripe.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/components/StripeGroup.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/fragments/StepOneFragment.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/fragments/StepStripesFragment.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/fragments/WelcomeFragment.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/utils/ColorPicker.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/utils/ColorPickerDialog.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/utils/ColorPickerPreference.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/utils/MultiColorPicker.java create mode 100644 app/src/main/res/drawable-hdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-hdpi/ic_action_settings.png create mode 100644 app/src/main/res/drawable-hdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-mdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_settings.png create mode 100644 app/src/main/res/drawable-mdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-nodpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-xhdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_settings.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_settings.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable/dimme.xml create mode 100644 app/src/main/res/layout/act_demo.xml create mode 100644 app/src/main/res/layout/act_multi_picker.xml create mode 100644 app/src/main/res/layout/act_picker.xml create mode 100644 app/src/main/res/layout/act_pref.xml create mode 100644 app/src/main/res/layout/activity_asistent.xml create mode 100644 app/src/main/res/layout/activity_color.xml create mode 100644 app/src/main/res/layout/drawer_fragment.xml create mode 100644 app/src/main/res/layout/fragment_step1.xml create mode 100644 app/src/main/res/layout/fragment_welcome.xml create mode 100644 app/src/main/res/layout/host_row.xml create mode 100644 app/src/main/res/layout/progress.xml create mode 100644 app/src/main/res/menu/color.xml create mode 100644 app/src/main/res/menu/step1.xml create mode 100644 app/src/main/res/menu/welcome.xml create mode 100644 app/src/main/res/values-sw600dp/dimens.xml create mode 100644 app/src/main/res/values-sw720dp-land/dimens.xml create mode 100644 app/src/main/res/values-v11/styles.xml create mode 100644 app/src/main/res/values-v14/styles.xml create mode 100644 app/src/main/res/values-v21/styles.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/main/res/xml/settings.xml create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 lombok.config create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..95ec4fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,140 @@ +# Created by https://www.gitignore.io + +### Gradle ### +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + + +### Linux ### +*~ + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + + +### Windows ### +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +### Android ### +# Built application files +*.apk +*.ap_ + +# Files for the Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ + +# Gradle files +.gradle/ +build/ +/*/build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +### Android Patch ### +gen-external-apklibs + + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties + + +### Java ### +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..538a8a1 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,45 @@ +buildscript { + repositories { + mavenCentral() + jcenter() + } + + dependencies { + classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1' + classpath 'com.github.ben-manes:gradle-versions-plugin:0.11.3' + } +} + +apply plugin: 'com.android.application' +apply plugin: 'com.jakewharton.hugo' +apply plugin: 'com.github.ben-manes.versions' + +android { + compileSdkVersion 22 + buildToolsVersion "22.0.1" + + defaultConfig { + applicationId "com.idlegandalf.ledd" + minSdkVersion 16 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:22.2.1' + compile 'com.android.support:support-v4:22.2.1' + compile 'com.squareup.okhttp:okhttp:2.4.0' + compile 'com.jakewharton:butterknife:7.0.1' + compile 'com.koushikdutta.async:androidasync:2.1.6' + compile 'com.android.support:design:22.2.1' + provided "org.projectlombok:lombok:1.16.4" +} diff --git a/app/proguard-rules.txt b/app/proguard-rules.txt new file mode 100644 index 0000000..e9ef993 --- /dev/null +++ b/app/proguard-rules.txt @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /home/giovanni/android-studio/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..0fcf6db --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/idlegandalf/ledd/AssistantActivity.java b/app/src/main/java/com/idlegandalf/ledd/AssistantActivity.java new file mode 100644 index 0000000..9a18c62 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/AssistantActivity.java @@ -0,0 +1,73 @@ +package com.idlegandalf.ledd; + +import android.app.Fragment; +import android.app.FragmentTransaction; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.Menu; +import android.widget.FrameLayout; + +import com.idlegandalf.ledd.fragments.WelcomeFragment; + +import butterknife.Bind; +import butterknife.ButterKnife; + +public class AssistantActivity extends AppCompatActivity { + + @Bind(R.id.fragmentContainer) + FrameLayout container; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_asistent); + ButterKnife.bind(this); + + // Check that the activity is using the layout version with + // the fragment_container FrameLayout + if (container != null) { + + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } + + // Create a new Fragment to be placed in the activity layout + WelcomeFragment welcomeFragment = new WelcomeFragment(); + + // In case this activity was started with special instructions from an + // Intent, pass the Intent's extras to the fragment as arguments + welcomeFragment.setArguments(getIntent().getExtras()); + + // Add the fragment to the 'fragment_container' FrameLayout + getFragmentManager().beginTransaction() + .add(R.id.fragmentContainer, welcomeFragment).commit(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.welcome, menu); + return true; + } + + public void switchFragment(Fragment fragment) { + FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); + + fragmentTransaction.replace(R.id.fragmentContainer, fragment); + fragmentTransaction.addToBackStack(null); + + fragmentTransaction.commit(); + } + + @Override + public void onBackPressed() { + if (getFragmentManager().getBackStackEntryCount() > 0) { + getFragmentManager().popBackStack(); + } else { + super.onBackPressed(); + } + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/ColorActivity.java b/app/src/main/java/com/idlegandalf/ledd/ColorActivity.java new file mode 100644 index 0000000..2020457 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/ColorActivity.java @@ -0,0 +1,147 @@ +package com.idlegandalf.ledd; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.app.AppCompatActivity; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; + +import com.idlegandalf.ledd.components.LEDDHelper; +import com.idlegandalf.ledd.components.RGBStripe; +import com.idlegandalf.ledd.components.StripeGroup; +import com.idlegandalf.ledd.utils.ColorPicker; + +import butterknife.Bind; +import butterknife.ButterKnife; + +public class ColorActivity extends AppCompatActivity { + + @Bind(R.id.colorPicker) + ColorPicker mWheel; + @Bind(R.id.drawer_layout) + DrawerLayout mDrawerLayout; + private ActionBarDrawerToggle mDrawerToggle; + private LEDDHelper mAPI; + private RGBStripe mActiveStripe; + private StripeGroup mActiveGroup; + private boolean firstRun = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_color); + ButterKnife.bind(this); + + // check for connectivity + ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + if (networkInfo == null || !networkInfo.isConnected()) { + // TODO: Display error + } + + mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.app_name, R.string.app_name) { + + /** Called when a drawer has settled in a completely closed state. */ + public void onDrawerClosed(View view) { + // TODO: do things that have to be done here + } + + /** Called when a drawer has settled in a completely open state. */ + public void onDrawerOpened(View drawerView) { + // TODO: do things that have to be done here + } + }; + + // set the drawer toggle as the DrawerListener + mDrawerLayout.setDrawerListener(mDrawerToggle); + + // enable Homebutton navigation to drawer + //getSupportActionBar().setDisplayHomeAsUpEnabled(true); + //getSupportActionBar().setHomeButtonEnabled(true); + // getSupportActionBar().setIcon(R.drawable.ic_bar); + + if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean( + "firstRun", true)) { + System.out.println("first run!"); + firstRun = true; + Intent intent = new Intent(this, AssistantActivity.class); + startActivity(intent); + } + + if (ColorApplication.getInstance().isAPIActive()) { + this.mAPI = ColorApplication.getInstance().getAPI(); + System.out.println("API active!"); + } else { + System.out.println("API not active :("); + this.finish(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.color, menu); + return true; + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + // Sync the toggle state after onRestoreInstanceState has occurred. + mDrawerToggle.syncState(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + mDrawerToggle.onConfigurationChanged(newConfig); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Pass the event to ActionBarDrawerToggle, if it returns + // true, then it has handled the app icon touch event + if (mDrawerToggle.onOptionsItemSelected(item)) { + return true; + } + // Handle your other action bar items... + + switch (item.getItemId()) { + case R.id.action_settings: + Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + return super.onOptionsItemSelected(item); + } + + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_MENU) { + if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) { + mDrawerLayout.closeDrawer(Gravity.LEFT); + } else { + mDrawerLayout.openDrawer(Gravity.LEFT); + } + + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/ColorApplication.java b/app/src/main/java/com/idlegandalf/ledd/ColorApplication.java new file mode 100644 index 0000000..2ce0b90 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/ColorApplication.java @@ -0,0 +1,55 @@ +package com.idlegandalf.ledd; + +import android.app.Application; +import android.preference.PreferenceManager; + +import com.idlegandalf.ledd.components.LEDDHelper; + +import java.io.IOException; + +public class ColorApplication extends Application { + private static ColorApplication singleton; + private LEDDHelper mAPI = null; + private boolean mAPIActive = false; + + public static ColorApplication getInstance() { + return singleton; + } + + @Override + public void onCreate() { + super.onCreate(); + singleton = this; + try { + initAPI(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public LEDDHelper getAPI() { + return this.mAPI; + } + + public void initAPI() throws IOException { + if (PreferenceManager.getDefaultSharedPreferences(this) + .contains("pref_key_host")) { + + mAPI = new LEDDHelper(PreferenceManager + .getDefaultSharedPreferences(this).getString( + "pref_key_host", ""), + PreferenceManager + .getDefaultSharedPreferences(this).getInt( + "pref_key_port", 8825), + getApplicationContext() + ); + + this.mAPIActive = true; + System.out.println("api is declared as active now"); + } + } + + public boolean isAPIActive() { + return mAPIActive; + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/ColorService.java b/app/src/main/java/com/idlegandalf/ledd/ColorService.java new file mode 100644 index 0000000..c5c137f --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/ColorService.java @@ -0,0 +1,99 @@ +package com.idlegandalf.ledd; + +import android.app.Service; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.widget.Toast; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +public class ColorService extends Service { + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + private DatagramSocket socket; + + // Handler that receives messages from the thread + private final class ServiceHandler extends Handler { + public ServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + Bundle msgdata = msg.getData(); + + if (msgdata != null) { + try { + byte[] data = msgdata.getString("json").getBytes(); + DatagramPacket packet = new DatagramPacket(data, data.length, + InetAddress.getByName(msgdata.getString("ip")), msgdata.getInt("port")); + socket.send(packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // Stop the service using the startId, so that we don't stop + // the service in the middle of handling another job + //stopSelf(msg.arg1); + } + } + + @Override + public void onCreate() { + Toast.makeText(this, "ColorService started", Toast.LENGTH_SHORT).show(); + + try { + socket = new DatagramSocket(); + } catch (SocketException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // Start up the thread running the service. Note that we create a + // separate thread because the service normally runs in the process's + // main thread, which we don't want to block. We also make it + // background priority so CPU-intensive work will not disrupt our UI. + HandlerThread thread = new HandlerThread("ServiceStartArguments", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + + // Get the HandlerThread's Looper and use it for our Handler + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + // For each start request, send a message to start a job and deliver the + // start ID so we know which request we're stopping when we finish the + // job + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + msg.setData(intent.getExtras()); + mServiceHandler.sendMessage(msg); + + // If we get killed, after returning from here, restart + return START_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + // We don't provide binding, so return null + return null; + } + + @Override + public void onDestroy() { + socket.close(); + Toast.makeText(this, "ColorService stopped", Toast.LENGTH_SHORT).show(); + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/DrawerFragment.java b/app/src/main/java/com/idlegandalf/ledd/DrawerFragment.java new file mode 100644 index 0000000..5187e2a --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/DrawerFragment.java @@ -0,0 +1,16 @@ +package com.idlegandalf.ledd; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public class DrawerFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.drawer_fragment, container, false); + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/ProgressBarActionBarActivity.java b/app/src/main/java/com/idlegandalf/ledd/ProgressBarActionBarActivity.java new file mode 100644 index 0000000..cfa606e --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/ProgressBarActionBarActivity.java @@ -0,0 +1,32 @@ +package com.idlegandalf.ledd; + +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; + +public abstract class ProgressBarActionBarActivity extends AppCompatActivity { + private ProgressBar mProgressBar; + + public void setContentView(View view) { + init().addView(view); + } + + public void setContentView(int layoutResID) { + getLayoutInflater().inflate(layoutResID, init(), true); + } + + public void setContentView(View view, ViewGroup.LayoutParams params) { + init().addView(view, params); + } + + private ViewGroup init() { + super.setContentView(R.layout.progress); + mProgressBar = (ProgressBar) findViewById(R.id.activity_bar); + return (ViewGroup) findViewById(R.id.activity_frame); + } + + protected ProgressBar getProgressBar() { + return mProgressBar; + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/SettingsActivity.java b/app/src/main/java/com/idlegandalf/ledd/SettingsActivity.java new file mode 100644 index 0000000..3f06731 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/SettingsActivity.java @@ -0,0 +1,17 @@ +package com.idlegandalf.ledd; + +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; + +public class SettingsActivity extends ActionBarActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + // Display the fragment as the main content. + getFragmentManager().beginTransaction() + .replace(android.R.id.content, new SettingsFragment()) + .commit(); + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/SettingsFragment.java b/app/src/main/java/com/idlegandalf/ledd/SettingsFragment.java new file mode 100644 index 0000000..0fe6fe8 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/SettingsFragment.java @@ -0,0 +1,14 @@ +package com.idlegandalf.ledd; + +import android.os.Bundle; +import android.preference.PreferenceFragment; + +public class SettingsFragment extends PreferenceFragment { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.settings); + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/components/Controller.java b/app/src/main/java/com/idlegandalf/ledd/components/Controller.java new file mode 100644 index 0000000..3192bf4 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/components/Controller.java @@ -0,0 +1,13 @@ +package com.idlegandalf.ledd.components; + +import java.util.ArrayList; + +import lombok.Getter; +import lombok.Setter; + + +@Getter +@Setter +public class Controller { + private ArrayList stripes; +} diff --git a/app/src/main/java/com/idlegandalf/ledd/components/HSV.java b/app/src/main/java/com/idlegandalf/ledd/components/HSV.java new file mode 100644 index 0000000..8cf72f6 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/components/HSV.java @@ -0,0 +1,12 @@ +package com.idlegandalf.ledd.components; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class HSV { + private float hue; + private float saturation; + private float value; +} diff --git a/app/src/main/java/com/idlegandalf/ledd/components/Host.java b/app/src/main/java/com/idlegandalf/ledd/components/Host.java new file mode 100644 index 0000000..6f98b79 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/components/Host.java @@ -0,0 +1,27 @@ +package com.idlegandalf.ledd.components; + + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Host { + private String address; + private int port; + + public Host(String address, int port) { + this.address = address; + this.port = port; + } + + public Host() { + this.address = null; + this.port = 0; + } + + @Override + public String toString() { + return address + ":" + port; + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/components/LEDDHelper.java b/app/src/main/java/com/idlegandalf/ledd/components/LEDDHelper.java new file mode 100644 index 0000000..85f06b1 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/components/LEDDHelper.java @@ -0,0 +1,68 @@ +package com.idlegandalf.ledd.components; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import com.idlegandalf.ledd.ColorService; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +public class LEDDHelper { + private String mAddr; + private int mPort; + private Context context; + + final String ACTION_SETCOLOR = "set_color"; + final String ACTION_GETCOLOR = "get_color"; + + public LEDDHelper(String ip, int port, Context appl) throws UnsupportedEncodingException, + IOException { + this.mAddr = ip; + this.mPort = port; + this.context = appl; + } + + /** + * Send RGB values to dameon using the stripeid + * @param sid Stripeid + * @param color Color in HSV format + * @throws JSONException not valid json + * @throws IOException socket error + */ + public void sendColor(int sid, HSV color) + throws JSONException, IOException { + JSONObject jnson = new JSONObject(); + JSONArray hsv = new JSONArray(); + + hsv.put(color.getHue()); + hsv.put(color.getSaturation()); + hsv.put(color.getValue()); + + jnson.put("action", ACTION_SETCOLOR); + jnson.put("sid", sid); + jnson.put("color", hsv); + + sendJSON(jnson.toString()); + } + + private void sendJSON(String json) throws IOException { + Intent intent = new Intent(context, ColorService.class); + Bundle bndl = new Bundle(); + bndl.putString("json", json); + bndl.putString("host", this.mAddr); + bndl.putInt("port", mPort); + intent.putExtras(bndl); + context.startService(intent); + } + + public void onDestroy() { + Intent intent = new Intent(context, ColorService.class); + context.stopService(intent); + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/components/RGBStripe.java b/app/src/main/java/com/idlegandalf/ledd/components/RGBStripe.java new file mode 100644 index 0000000..d964868 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/components/RGBStripe.java @@ -0,0 +1,17 @@ +package com.idlegandalf.ledd.components; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RGBStripe { + private int id; + private int channelRed; + private int channelGreen; + private int channelBlue; + private String nice_name; + private HSV color; + private double gammaCorrection; + +} \ No newline at end of file diff --git a/app/src/main/java/com/idlegandalf/ledd/components/StripeGroup.java b/app/src/main/java/com/idlegandalf/ledd/components/StripeGroup.java new file mode 100644 index 0000000..d625d53 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/components/StripeGroup.java @@ -0,0 +1,62 @@ +package com.idlegandalf.ledd.components; + + +import org.json.JSONException; + +import java.io.IOException; +import java.util.ArrayList; + +public class StripeGroup { + private String mNiceName; + private String mDescription; + private ArrayList mStripes; + + public String getNiceName() { + return mNiceName; + } + + public void setNiceName(String mNiceName) { + this.mNiceName = mNiceName; + } + + public String getDescription() { + return mDescription; + } + + public void setDescription(String mDescription) { + this.mDescription = mDescription; + } + + public RGBStripe getStripeByPos(int pos) { + return mStripes.get(pos); + } + + public RGBStripe getStripeById(int sid) { + for (int i = 0; i < mStripes.size(); i++) { + if (mStripes.get(i).getId() == sid) { + return mStripes.get(i); + } + } + return null; + } + + public void setRGB(int r, int g, int b, LEDDHelper api) throws JSONException, IOException { + for (int i = 0; i < mStripes.size(); i++) { + //mStripes.get(i).setRGB(r, g, b, api); + } + } + + public int addStripe(RGBStripe stripe) { + mStripes.add(stripe); + return mStripes.size()-1; + } + + public void removeStripeByObject(RGBStripe stripe) { + for (int i = 0; i < mStripes.size(); i++) { + if (mStripes.get(i).getId() == stripe.getId()) { + mStripes.remove(i); + return; + } + } + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/fragments/StepOneFragment.java b/app/src/main/java/com/idlegandalf/ledd/fragments/StepOneFragment.java new file mode 100644 index 0000000..91491af --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/fragments/StepOneFragment.java @@ -0,0 +1,233 @@ +package com.idlegandalf.ledd.fragments; + +import android.app.Fragment; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import com.idlegandalf.ledd.R; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.util.ArrayList; + +import butterknife.Bind; +import butterknife.ButterKnife; + +public class StepOneFragment extends Fragment { + @Bind(R.id.step2_back) + Button mBack; + @Bind(R.id.ipSelect) + EditText mAutoIP; + @Bind(R.id.step2_next) + Button mTest; + @Bind(R.id.portSelect) + EditText mAutoPort; + ArrayList mIPList = new ArrayList<>(); + boolean isAutoDetected = false; + + + public static StepOneFragment newInstance(String addrs) { + Bundle args = new Bundle(); + + args.putString("ips", addrs); + + StepOneFragment fragment = new StepOneFragment(); + fragment.setArguments(args); + return fragment; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_step1, container, false); + ButterKnife.bind(this, v); + + return v; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + String ips = getArguments().getString("ips"); + + if (ips != null) { + if (!ips.isEmpty()) { + for (String string : ips.split(";")) { + if (string.isEmpty()) { + System.out.println("added addr " + string); + mIPList.add(string); + } + } + if (mIPList.size() > 0) isAutoDetected = true; + } + } + + mBack.setOnClickListener(nextClickListener); + mTest.setOnClickListener(nextClickListener); + } + + private OnClickListener nextClickListener = new OnClickListener() { + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.step2_back: + getActivity().onBackPressed(); + break; + case R.id.step2_next: + System.out.println("forward calling!"); + testController(); + break; + default: + break; + } + } + }; + + private void testController() { + ConnectivityManager connManager = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + + if (mWifi.isConnected()) { + setInputState(false); + if (!isValidAddrInput(mAutoIP, mAutoPort)) { + setInputState(true); + return; + } + getActivity().setProgressBarIndeterminateVisibility(true); + getActivity().setProgressBarVisibility(true); + new pokeController().execute(mAutoIP.toString(), mAutoPort.toString()); + } else { + Toast.makeText(getActivity().getApplicationContext(), "please connect WiFi", Toast.LENGTH_LONG).show(); + } + } + + private class pokeController extends AsyncTask { + protected Boolean doInBackground(String... ippo) { + try { + InetAddress controller = InetAddress.getByName(ippo[0]); + int port = Integer.parseInt(ippo[1]); + + DatagramSocket socket = new DatagramSocket(); + String hstr = new JSONObject().put("action", 5).toString(); + + DatagramPacket hello = new DatagramPacket(hstr.getBytes(), hstr.getBytes().length); + + hello.setPort(port); + socket.setSoTimeout(100); + + if (!controller.isReachable(50)) { + socket.close(); + return false; + } + + hello.setAddress(controller); + socket.send(hello); + + DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); + try { + socket.receive(packet); + } catch (SocketTimeoutException e) { + socket.close(); + return false; + } + + Toast.makeText(getActivity().getApplicationContext(), new String(packet.getData(), 0, packet.getLength()), Toast.LENGTH_LONG).show(); + + JSONObject resjson = new JSONObject(new String(packet.getData(), 0, packet.getLength())); + + if (resjson.getInt("action") != 5) { + socket.close(); + return false; + } + + socket.close(); + } catch (SocketException e1) { + return false; + } catch (IOException e1) { + return false; + } catch (JSONException e) { + return false; + } + + return true; + } + + protected void onProgressUpdate(Void... progress) { + + } + + protected void onPostExecute(Boolean result) { + getActivity().setProgressBarIndeterminateVisibility(false); + getActivity().setProgressBarVisibility(false); + setInputState(true); + if (result) { + Snackbar.make(getActivity().findViewById(R.id.linlayp), "found daemon running on " + + "address " + mAutoIP.toString() + ":" + mAutoPort.toString(), Snackbar.LENGTH_LONG).show(); + } else { + Snackbar.make(getActivity().findViewById(R.id.linlayp), "No running daemon " + "found", Snackbar.LENGTH_LONG).show(); + } + } + } + + private boolean isValidIPFromEditText(EditText atv) { + String exip[] = atv.toString().trim().split("\\."); + if (exip.length != 4) return false; + + for (String string : exip) { + if (!string.isEmpty()) { + try { + if (Integer.parseInt(string) < 0 || Integer.parseInt(string) > 255) return false; + } catch (NumberFormatException e) { + return false; + } + } + } + + return true; + } + + private boolean isValidPortFromEditText(EditText atv) { + return !atv.toString().isEmpty() && Integer.parseInt(atv.toString()) > 1023 && Integer.parseInt(atv.toString()) <= 65535; + } + + private boolean isValidAddrInput(EditText ipatv, EditText portatv) { + if (!isValidIPFromEditText(ipatv)) { + Snackbar.make(getActivity().findViewById(R.id.linlayp), "Please enter valid IP " + "address", Snackbar.LENGTH_LONG).show(); + + return false; + } + if (!isValidPortFromEditText(portatv)) { + Snackbar.make(getActivity().findViewById(R.id.linlayp), "Please enter valid port " + "(1024-65535)", Snackbar.LENGTH_LONG).show(); + + return false; + } + return true; + } + + private void setInputState(boolean state) { + mAutoIP.setEnabled(state); + mAutoPort.setEnabled(state); + mBack.setEnabled(state); + mTest.setEnabled(state); + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/fragments/StepStripesFragment.java b/app/src/main/java/com/idlegandalf/ledd/fragments/StepStripesFragment.java new file mode 100644 index 0000000..1e8ecc5 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/fragments/StepStripesFragment.java @@ -0,0 +1,7 @@ +package com.idlegandalf.ledd.fragments; + +import android.app.Fragment; + +public class StepStripesFragment extends Fragment { + +} diff --git a/app/src/main/java/com/idlegandalf/ledd/fragments/WelcomeFragment.java b/app/src/main/java/com/idlegandalf/ledd/fragments/WelcomeFragment.java new file mode 100644 index 0000000..b63ac5c --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/fragments/WelcomeFragment.java @@ -0,0 +1,218 @@ +package com.idlegandalf.ledd.fragments; + +import android.app.Fragment; +import android.content.Context; +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.idlegandalf.ledd.AssistantActivity; +import com.idlegandalf.ledd.R; +import com.idlegandalf.ledd.components.Host; + +import java.net.Inet4Address; +import java.util.ArrayList; + +import butterknife.Bind; +import butterknife.ButterKnife; + +public class WelcomeFragment extends Fragment { + + @Bind(R.id.step1_auto) + Button mAuto; + @Bind(R.id.step1_manual) + Button mManual; + @Bind(R.id.host_container) + LinearLayout hostContainer; + @Bind(R.id.toolbar) + Toolbar toolbar; + + NsdManager mNsdManager; + final String TAG = "ColorD"; + NsdManager.DiscoveryListener mDiscoveryListener; + NsdManager.ResolveListener mResolveListener; + ArrayList hosts; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_welcome, container, false); + ButterKnife.bind(this, v); + return v; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + mAuto.setOnClickListener(nextClickListener); + mManual.setOnClickListener(nextClickListener); + + ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar); + + hosts = new ArrayList<>(); + + mResolveListener = new NsdManager.ResolveListener() { + + @Override + public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { + // Called when the resolve fails. Use the error code to debug. + Log.e(TAG, "Resolve failed" + errorCode); + } + + @Override + public void onServiceResolved(final NsdServiceInfo serviceInfo) { + Log.e(TAG, "Resolve Succeeded. " + serviceInfo); + + if (serviceInfo.getHost() instanceof Inet4Address) { + Log.d(TAG, "Found IPv4! Yay!"); + + final Host fHost = new Host(serviceInfo.getHost().getHostAddress(), serviceInfo.getPort()); + + if (!hosts.contains(fHost)) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + View v = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout + .host_row, hostContainer, false); + + TextView host = (TextView) v.findViewById(R.id.welcome_host); + + host.setText(serviceInfo.getHost().getHostAddress() + ":" + serviceInfo.getPort()); + host.setTag(serviceInfo); + + View.OnClickListener listener = new View.OnClickListener() { + @Override + public void onClick(View v) { + StepOneFragment stepOneFragment = StepOneFragment.newInstance(hosts.get((int) v.getTag()).toString()); + ((AssistantActivity) getActivity()).switchFragment(stepOneFragment); + } + }; + + v.setOnClickListener(listener); + host.setOnClickListener(listener); + + v.setTag(hosts.size()); + host.setTag(hosts.size()); + + hostContainer.addView(v); + hosts.add(fHost); + } + }); + } + } + } + }; + + mDiscoveryListener = new NsdManager.DiscoveryListener() { + + // Called as soon as service discovery begins. + @Override + public void onDiscoveryStarted(String regType) { + Log.d(TAG, "Service discovery started"); + } + + @Override + public void onServiceFound(NsdServiceInfo service) { + // A service was found! Do something with it. + Log.d(TAG, "Service discovery success " + service); + if (!service.getServiceType().equals("_ledd._tcp.")) { + // Service type is the string containing the protocol and + // transport layer for this service. + Log.d(TAG, "Unknown Service Type: " + service.getServiceType()); + } else { + mNsdManager.resolveService(service, mResolveListener); + } + } + + @Override + public void onServiceLost(NsdServiceInfo service) { + // When the network service is no longer available. + // Internal bookkeeping code goes here. + Log.e(TAG, "service lost" + service); + } + + @Override + public void onDiscoveryStopped(String serviceType) { + Log.i(TAG, "Discovery stopped: " + serviceType); + } + + @Override + public void onStartDiscoveryFailed(String serviceType, int errorCode) { + Log.e(TAG, "Discovery failed: Error code:" + errorCode); + mNsdManager.stopServiceDiscovery(this); + } + + @Override + public void onStopDiscoveryFailed(String serviceType, int errorCode) { + Log.e(TAG, "Discovery failed: Error code:" + errorCode); + mNsdManager.stopServiceDiscovery(this); + } + }; + } + + private View.OnClickListener nextClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.step1_auto: + System.out.println("auto pressed"); + //getProgressBar().setIndeterminate(true); + //setProgressBarIndeterminateVisibility(true); + //setProgressBarVisibility(true); + //setProgressBarIndeterminate(true); + setButtonState(false); + + mNsdManager = (NsdManager) getActivity().getSystemService(Context.NSD_SERVICE); + mNsdManager.discoverServices("_ledd._tcp", NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener); + + break; + case R.id.step1_manual: + System.out.println("manual pressed"); + setButtonState(false); + StepOneFragment stepOneFragment = StepOneFragment.newInstance(null); + ((AssistantActivity) getActivity()).switchFragment(stepOneFragment); + setButtonState(true); + break; + default: + break; + } + } + }; + + void setButtonState(boolean state) { + mAuto.setEnabled(state); + mManual.setEnabled(state); + } + + @Override + public void onPause() { + if (mNsdManager != null) { + tearDown(); + setButtonState(true); + } + + super.onPause(); + } + + @Override + public void onDestroy() { + if (mNsdManager != null) tearDown(); + super.onDestroy(); + } + + // NsdHelper's tearDown method + public void tearDown() { + mNsdManager.stopServiceDiscovery(mDiscoveryListener); + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/utils/ColorPicker.java b/app/src/main/java/com/idlegandalf/ledd/utils/ColorPicker.java new file mode 100644 index 0000000..52ebfd6 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/utils/ColorPicker.java @@ -0,0 +1,352 @@ +/* + * Copyright 2013 Piotr Adamus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.idlegandalf.ledd.utils; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ComposeShader; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Paint.Join; +import android.graphics.Paint.Style; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.RadialGradient; +import android.graphics.RectF; +import android.graphics.Shader.TileMode; +import android.graphics.SweepGradient; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +public class ColorPicker extends View { + + /** + * Customizable display parameters (in percents) + */ + private final int paramOuterPadding = 2; // outer padding of the whole color picker view + private final int paramInnerPadding = 5; // distance between value slider wheel and inner color wheel + private final int paramValueSliderWidth = 10; // width of the value slider + private final int paramArrowPointerSize = 4; // size of the arrow pointer; set to 0 to hide the pointer + + private Paint colorWheelPaint; + private Paint valueSliderPaint; + + private Paint colorViewPaint; + + private Paint colorPointerPaint; + private RectF colorPointerCoords; + + private Paint valuePointerPaint; + private Paint valuePointerArrowPaint; + + private RectF outerWheelRect; + private RectF innerWheelRect; + + private Path colorViewPath; + private Path valueSliderPath; + private Path arrowPointerPath; + + private Bitmap colorWheelBitmap; + + private int valueSliderWidth; + private int innerPadding; + private int outerPadding; + + private int arrowPointerSize; + private int outerWheelRadius; + private int innerWheelRadius; + private int colorWheelRadius; + + private Matrix gradientRotationMatrix; + + /** Currently selected color */ + private float[] colorHSV = new float[] { 0f, 0f, 1f }; + + public ColorPicker(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public ColorPicker(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public ColorPicker(Context context) { + super(context); + init(); + } + + private void init() { + + colorPointerPaint = new Paint(); + colorPointerPaint.setStyle(Style.STROKE); + colorPointerPaint.setStrokeWidth(2f); + colorPointerPaint.setARGB(128, 0, 0, 0); + + valuePointerPaint = new Paint(); + valuePointerPaint.setStyle(Style.STROKE); + valuePointerPaint.setStrokeWidth(2f); + + valuePointerArrowPaint = new Paint(); + + colorWheelPaint = new Paint(); + colorWheelPaint.setAntiAlias(true); + colorWheelPaint.setDither(true); + + valueSliderPaint = new Paint(); + valueSliderPaint.setAntiAlias(true); + valueSliderPaint.setDither(true); + + colorViewPaint = new Paint(); + colorViewPaint.setAntiAlias(true); + + colorViewPath = new Path(); + valueSliderPath = new Path(); + arrowPointerPath = new Path(); + + outerWheelRect = new RectF(); + innerWheelRect = new RectF(); + + colorPointerCoords = new RectF(); + + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + int size = Math.min(widthSize, heightSize); + setMeasuredDimension(size, size); + } + + @SuppressLint("DrawAllocation") + @Override + protected void onDraw(Canvas canvas) { + + int centerX = getWidth() / 2; + int centerY = getHeight() / 2; + + // drawing color wheel + + canvas.drawBitmap(colorWheelBitmap, centerX - colorWheelRadius, centerY - colorWheelRadius, null); + + // drawing color view + + colorViewPaint.setColor(Color.HSVToColor(colorHSV)); + canvas.drawPath(colorViewPath, colorViewPaint); + + // drawing value slider + + float[] hsv = new float[] { colorHSV[0], colorHSV[1], 1f }; + + SweepGradient sweepGradient = new SweepGradient(centerX, centerY, new int[] { Color.BLACK, Color.HSVToColor(hsv), Color.WHITE }, null); + sweepGradient.setLocalMatrix(gradientRotationMatrix); + valueSliderPaint.setShader(sweepGradient); + + canvas.drawPath(valueSliderPath, valueSliderPaint); + + // drawing color wheel pointer + + float hueAngle = (float) Math.toRadians(colorHSV[0]); + int colorPointX = (int) (-Math.cos(hueAngle) * colorHSV[1] * colorWheelRadius) + centerX; + int colorPointY = (int) (-Math.sin(hueAngle) * colorHSV[1] * colorWheelRadius) + centerY; + + float pointerRadius = 0.075f * colorWheelRadius; + int pointerX = (int) (colorPointX - pointerRadius / 2); + int pointerY = (int) (colorPointY - pointerRadius / 2); + + colorPointerCoords.set(pointerX, pointerY, pointerX + pointerRadius, pointerY + pointerRadius); + canvas.drawOval(colorPointerCoords, colorPointerPaint); + + // drawing value pointer + + valuePointerPaint.setColor(Color.HSVToColor(new float[] { 0f, 0f, 1f - colorHSV[2] })); + + double valueAngle = (colorHSV[2] - 0.5f) * Math.PI; + float valueAngleX = (float) Math.cos(valueAngle); + float valueAngleY = (float) Math.sin(valueAngle); + + canvas.drawLine(valueAngleX * innerWheelRadius + centerX, valueAngleY * innerWheelRadius + centerY, valueAngleX * outerWheelRadius + centerX, + valueAngleY * outerWheelRadius + centerY, valuePointerPaint); + + // drawing pointer arrow + + if (arrowPointerSize > 0) { + drawPointerArrow(canvas); + } + + } + + private void drawPointerArrow(Canvas canvas) { + + int centerX = getWidth() / 2; + int centerY = getHeight() / 2; + + double tipAngle = (colorHSV[2] - 0.5f) * Math.PI; + double leftAngle = tipAngle + Math.PI / 96; + double rightAngle = tipAngle - Math.PI / 96; + + double tipAngleX = Math.cos(tipAngle) * outerWheelRadius; + double tipAngleY = Math.sin(tipAngle) * outerWheelRadius; + double leftAngleX = Math.cos(leftAngle) * (outerWheelRadius + arrowPointerSize); + double leftAngleY = Math.sin(leftAngle) * (outerWheelRadius + arrowPointerSize); + double rightAngleX = Math.cos(rightAngle) * (outerWheelRadius + arrowPointerSize); + double rightAngleY = Math.sin(rightAngle) * (outerWheelRadius + arrowPointerSize); + + arrowPointerPath.reset(); + arrowPointerPath.moveTo((float) tipAngleX + centerX, (float) tipAngleY + centerY); + arrowPointerPath.lineTo((float) leftAngleX + centerX, (float) leftAngleY + centerY); + arrowPointerPath.lineTo((float) rightAngleX + centerX, (float) rightAngleY + centerY); + arrowPointerPath.lineTo((float) tipAngleX + centerX, (float) tipAngleY + centerY); + + valuePointerArrowPaint.setColor(Color.HSVToColor(colorHSV)); + valuePointerArrowPaint.setStyle(Style.FILL); + canvas.drawPath(arrowPointerPath, valuePointerArrowPaint); + + valuePointerArrowPaint.setStyle(Style.STROKE); + valuePointerArrowPaint.setStrokeJoin(Join.ROUND); + valuePointerArrowPaint.setColor(Color.BLACK); + canvas.drawPath(arrowPointerPath, valuePointerArrowPaint); + + } + + @Override + protected void onSizeChanged(int width, int height, int oldw, int oldh) { + + int centerX = width / 2; + int centerY = height / 2; + + innerPadding = (int) (paramInnerPadding * width / 100); + outerPadding = (int) (paramOuterPadding * width / 100); + arrowPointerSize = (int) (paramArrowPointerSize * width / 100); + valueSliderWidth = (int) (paramValueSliderWidth * width / 100); + + outerWheelRadius = width / 2 - outerPadding - arrowPointerSize; + innerWheelRadius = outerWheelRadius - valueSliderWidth; + colorWheelRadius = innerWheelRadius - innerPadding; + + outerWheelRect.set(centerX - outerWheelRadius, centerY - outerWheelRadius, centerX + outerWheelRadius, centerY + outerWheelRadius); + innerWheelRect.set(centerX - innerWheelRadius, centerY - innerWheelRadius, centerX + innerWheelRadius, centerY + innerWheelRadius); + + colorWheelBitmap = createColorWheelBitmap(colorWheelRadius * 2, colorWheelRadius * 2); + + gradientRotationMatrix = new Matrix(); + gradientRotationMatrix.preRotate(270, width / 2, height / 2); + + colorViewPath.arcTo(outerWheelRect, 270, -180); + colorViewPath.arcTo(innerWheelRect, 90, 180); + + valueSliderPath.arcTo(outerWheelRect, 270, 180); + valueSliderPath.arcTo(innerWheelRect, 90, -180); + + } + + private Bitmap createColorWheelBitmap(int width, int height) { + + Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); + + int colorCount = 12; + int colorAngleStep = 360 / 12; + int colors[] = new int[colorCount + 1]; + float hsv[] = new float[] { 0f, 1f, 1f }; + for (int i = 0; i < colors.length; i++) { + hsv[0] = (i * colorAngleStep + 180) % 360; + colors[i] = Color.HSVToColor(hsv); + } + colors[colorCount] = colors[0]; + + SweepGradient sweepGradient = new SweepGradient(width / 2, height / 2, colors, null); + RadialGradient radialGradient = new RadialGradient(width / 2, height / 2, colorWheelRadius, 0xFFFFFFFF, 0x00FFFFFF, TileMode.CLAMP); + ComposeShader composeShader = new ComposeShader(sweepGradient, radialGradient, PorterDuff.Mode.SRC_OVER); + + colorWheelPaint.setShader(composeShader); + + Canvas canvas = new Canvas(bitmap); + canvas.drawCircle(width / 2, height / 2, colorWheelRadius, colorWheelPaint); + + return bitmap; + + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + + int x = (int) event.getX(); + int y = (int) event.getY(); + int cx = x - getWidth() / 2; + int cy = y - getHeight() / 2; + double d = Math.sqrt(cx * cx + cy * cy); + + if (d <= colorWheelRadius) { + + colorHSV[0] = (float) (Math.toDegrees(Math.atan2(cy, cx)) + 180f); + colorHSV[1] = Math.max(0f, Math.min(1f, (float) (d / colorWheelRadius))); + + invalidate(); + + } else if (x >= getWidth() / 2 && d >= innerWheelRadius) { + + colorHSV[2] = (float) Math.max(0, Math.min(1, Math.atan2(cy, cx) / Math.PI + 0.5f)); + + invalidate(); + } + + return true; + } + return super.onTouchEvent(event); + } + + public void setColor(int color) { + Color.colorToHSV(color, colorHSV); + } + + public int getColor() { + return Color.HSVToColor(colorHSV); + } + + @Override + protected Parcelable onSaveInstanceState() { + Bundle state = new Bundle(); + state.putFloatArray("color", colorHSV); + state.putParcelable("super", super.onSaveInstanceState()); + return state; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + colorHSV = bundle.getFloatArray("color"); + super.onRestoreInstanceState(bundle.getParcelable("super")); + } else { + super.onRestoreInstanceState(state); + } + } + +} diff --git a/app/src/main/java/com/idlegandalf/ledd/utils/ColorPickerDialog.java b/app/src/main/java/com/idlegandalf/ledd/utils/ColorPickerDialog.java new file mode 100644 index 0000000..097d2f1 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/utils/ColorPickerDialog.java @@ -0,0 +1,54 @@ +package com.idlegandalf.ledd.utils; + + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.widget.RelativeLayout; +import android.widget.RelativeLayout.LayoutParams; + +public class ColorPickerDialog extends AlertDialog { + + private ColorPicker colorPickerView; + private final OnColorSelectedListener onColorSelectedListener; + + public ColorPickerDialog(Context context, int initialColor, OnColorSelectedListener onColorSelectedListener) { + super(context); + + this.onColorSelectedListener = onColorSelectedListener; + + RelativeLayout relativeLayout = new RelativeLayout(context); + LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); + + colorPickerView = new ColorPicker(context); + colorPickerView.setColor(initialColor); + + relativeLayout.addView(colorPickerView, layoutParams); + + setButton(BUTTON_POSITIVE, context.getString(android.R.string.ok), onClickListener); + setButton(BUTTON_NEGATIVE, context.getString(android.R.string.cancel), onClickListener); + + setView(relativeLayout); + + } + + private OnClickListener onClickListener = new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case BUTTON_POSITIVE: + int selectedColor = colorPickerView.getColor(); + onColorSelectedListener.onColorSelected(selectedColor); + break; + case BUTTON_NEGATIVE: + dialog.dismiss(); + break; + } + } + }; + + public interface OnColorSelectedListener { + public void onColorSelected(int color); + } + +} diff --git a/app/src/main/java/com/idlegandalf/ledd/utils/ColorPickerPreference.java b/app/src/main/java/com/idlegandalf/ledd/utils/ColorPickerPreference.java new file mode 100644 index 0000000..576b0c0 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/utils/ColorPickerPreference.java @@ -0,0 +1,73 @@ +package com.idlegandalf.ledd.utils; + + +import android.app.AlertDialog.Builder; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.RelativeLayout.LayoutParams; + +public class ColorPickerPreference extends DialogPreference { + + public static final int DEFAULT_COLOR = Color.WHITE; + + private int selectedColor; + private ColorPicker colorPickerView; + + public ColorPickerPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected View onCreateDialogView() { + + RelativeLayout relativeLayout = new RelativeLayout(getContext()); + LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); + + colorPickerView = new ColorPicker(getContext()); + colorPickerView.setId(1); + + relativeLayout.addView(colorPickerView, layoutParams); + + return relativeLayout; + + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + colorPickerView.setColor(selectedColor); + } + + @Override + protected void onPrepareDialogBuilder(Builder builder) { + super.onPrepareDialogBuilder(builder); + builder.setTitle(null); // remove dialog title to get more space for color picker + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + if (positiveResult && shouldPersist()) { + if (callChangeListener(colorPickerView.getColor())) { + selectedColor = colorPickerView.getColor(); + persistInt(selectedColor); + } + } + } + + @Override + protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { + selectedColor = restoreValue ? getPersistedInt(DEFAULT_COLOR) : (Integer) defaultValue; + } + + @Override + protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getInt(index, DEFAULT_COLOR); + } + +} diff --git a/app/src/main/java/com/idlegandalf/ledd/utils/MultiColorPicker.java b/app/src/main/java/com/idlegandalf/ledd/utils/MultiColorPicker.java new file mode 100644 index 0000000..b6a20fe --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/utils/MultiColorPicker.java @@ -0,0 +1,401 @@ +/* + * Copyright 2013 Piotr Adamus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.idlegandalf.ledd.utils; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ComposeShader; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Paint.Join; +import android.graphics.Paint.Style; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.RadialGradient; +import android.graphics.RectF; +import android.graphics.Shader.TileMode; +import android.graphics.SweepGradient; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +public class MultiColorPicker extends View { + + /** + * Customizable display parameters (in percents) + */ + private final int paramOuterPadding = 2; // outer padding of the whole color picker view + private final int paramInnerPadding = 5; // distance between value slider wheel and inner color wheel + private final int paramValueSliderWidth = 10; // width of the value slider + private final int paramArrowPointerSize = 4; // size of the arrow pointer; set to 0 to hide the pointer + + private final int paramColorCount = 5; + private final float paramHueSpreadAngle = 30f; // in degrees + + private Paint colorWheelPaint; + private Paint valueSliderPaint; + + private Paint colorViewPaint; + + private Paint colorPointerPaint; + private RectF colorPointerCoords; + + private Paint valuePointerPaint; + private Paint valuePointerArrowPaint; + + private RectF outerWheelRect; + private RectF innerWheelRect; + + private Path colorViewPath; + private Path valueSliderPath; + private Path arrowPointerPath; + + private Bitmap colorWheelBitmap; + + private int valueSliderWidth; + private int innerPadding; + private int outerPadding; + + private int arrowPointerSize; + private int outerWheelRadius; + private int innerWheelRadius; + private int colorWheelRadius; + + private Matrix gradientRotationMatrix; + + /** Currently selected color */ + private float[] colorHSV = new float[] { 0f, 0f, 1f }; + private float[] adjacentHue = new float[paramColorCount]; + + public MultiColorPicker(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public MultiColorPicker(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public MultiColorPicker(Context context) { + super(context); + init(); + } + + private void init() { + + colorPointerPaint = new Paint(); + colorPointerPaint.setStyle(Style.STROKE); + colorPointerPaint.setStrokeWidth(2f); + colorPointerPaint.setARGB(128, 0, 0, 0); + + valuePointerPaint = new Paint(); + valuePointerPaint.setStyle(Style.STROKE); + valuePointerPaint.setStrokeWidth(2f); + + valuePointerArrowPaint = new Paint(); + + colorWheelPaint = new Paint(); + colorWheelPaint.setAntiAlias(true); + colorWheelPaint.setDither(true); + + valueSliderPaint = new Paint(); + valueSliderPaint.setAntiAlias(true); + valueSliderPaint.setDither(true); + + colorViewPaint = new Paint(); + colorViewPaint.setAntiAlias(true); + + colorViewPath = new Path(); + valueSliderPath = new Path(); + arrowPointerPath = new Path(); + + outerWheelRect = new RectF(); + innerWheelRect = new RectF(); + + colorPointerCoords = new RectF(); + + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + int size = Math.min(widthSize, heightSize); + setMeasuredDimension(size, size); + } + + @SuppressLint("DrawAllocation") + @Override + protected void onDraw(Canvas canvas) { + + int centerX = getWidth() / 2; + int centerY = getHeight() / 2; + + // drawing color wheel + + canvas.drawBitmap(colorWheelBitmap, centerX - colorWheelRadius, centerY - colorWheelRadius, null); + + // drawing color view + + int[] segmentColors = getColors(); + float sweepAngleStep = 180f / paramColorCount; + for (int i = 0; i < paramColorCount; i++) { + + colorViewPath.reset(); + colorViewPath.arcTo(outerWheelRect, 270 - i * sweepAngleStep, -sweepAngleStep); + colorViewPath.arcTo(innerWheelRect, 90 + (paramColorCount - i - 1) * sweepAngleStep, sweepAngleStep); + + colorViewPaint.setColor(segmentColors[i]); + + canvas.drawPath(colorViewPath, colorViewPaint); + + } + + // drawing value slider + + float[] hsv = new float[] { colorHSV[0], colorHSV[1], 1f }; + + SweepGradient sweepGradient = new SweepGradient(centerX, centerY, new int[] { Color.BLACK, Color.HSVToColor(hsv), Color.WHITE }, null); + sweepGradient.setLocalMatrix(gradientRotationMatrix); + valueSliderPaint.setShader(sweepGradient); + + canvas.drawPath(valueSliderPath, valueSliderPaint); + + // drawing color wheel pointer + + for (int i = 0; i < paramColorCount; i++) { + drawColorWheelPointer(canvas, (float) Math.toRadians(adjacentHue[i])); + } + + // drawing value pointer + + valuePointerPaint.setColor(Color.HSVToColor(new float[] { 0f, 0f, 1f - colorHSV[2] })); + + double valueAngle = (colorHSV[2] - 0.5f) * Math.PI; + float valueAngleX = (float) Math.cos(valueAngle); + float valueAngleY = (float) Math.sin(valueAngle); + + canvas.drawLine(valueAngleX * innerWheelRadius + centerX, valueAngleY * innerWheelRadius + centerY, valueAngleX * outerWheelRadius + centerX, + valueAngleY * outerWheelRadius + centerY, valuePointerPaint); + + // drawing pointer arrow + + if (arrowPointerSize > 0) { + drawPointerArrow(canvas); + } + + } + + private void drawColorWheelPointer(Canvas canvas, float hueAngle) { + + int centerX = getWidth() / 2; + int centerY = getHeight() / 2; + + int colorPointX = (int) (-Math.cos(hueAngle) * colorHSV[1] * colorWheelRadius) + centerX; + int colorPointY = (int) (-Math.sin(hueAngle) * colorHSV[1] * colorWheelRadius) + centerY; + + float pointerRadius = 0.075f * colorWheelRadius; + int pointerX = (int) (colorPointX - pointerRadius / 2); + int pointerY = (int) (colorPointY - pointerRadius / 2); + + colorPointerCoords.set(pointerX, pointerY, pointerX + pointerRadius, pointerY + pointerRadius); + canvas.drawOval(colorPointerCoords, colorPointerPaint); + + } + + private void drawPointerArrow(Canvas canvas) { + + int centerX = getWidth() / 2; + int centerY = getHeight() / 2; + + double tipAngle = (colorHSV[2] - 0.5f) * Math.PI; + double leftAngle = tipAngle + Math.PI / 96; + double rightAngle = tipAngle - Math.PI / 96; + + double tipAngleX = Math.cos(tipAngle) * outerWheelRadius; + double tipAngleY = Math.sin(tipAngle) * outerWheelRadius; + double leftAngleX = Math.cos(leftAngle) * (outerWheelRadius + arrowPointerSize); + double leftAngleY = Math.sin(leftAngle) * (outerWheelRadius + arrowPointerSize); + double rightAngleX = Math.cos(rightAngle) * (outerWheelRadius + arrowPointerSize); + double rightAngleY = Math.sin(rightAngle) * (outerWheelRadius + arrowPointerSize); + + arrowPointerPath.reset(); + arrowPointerPath.moveTo((float) tipAngleX + centerX, (float) tipAngleY + centerY); + arrowPointerPath.lineTo((float) leftAngleX + centerX, (float) leftAngleY + centerY); + arrowPointerPath.lineTo((float) rightAngleX + centerX, (float) rightAngleY + centerY); + arrowPointerPath.lineTo((float) tipAngleX + centerX, (float) tipAngleY + centerY); + + valuePointerArrowPaint.setColor(Color.HSVToColor(colorHSV)); + valuePointerArrowPaint.setStyle(Style.FILL); + canvas.drawPath(arrowPointerPath, valuePointerArrowPaint); + + valuePointerArrowPaint.setStyle(Style.STROKE); + valuePointerArrowPaint.setStrokeJoin(Join.ROUND); + valuePointerArrowPaint.setColor(Color.BLACK); + canvas.drawPath(arrowPointerPath, valuePointerArrowPaint); + + } + + @Override + protected void onSizeChanged(int width, int height, int oldw, int oldh) { + + int centerX = width / 2; + int centerY = height / 2; + + innerPadding = (int) (paramInnerPadding * width / 100); + outerPadding = (int) (paramOuterPadding * width / 100); + arrowPointerSize = (int) (paramArrowPointerSize * width / 100); + valueSliderWidth = (int) (paramValueSliderWidth * width / 100); + + outerWheelRadius = width / 2 - outerPadding - arrowPointerSize; + innerWheelRadius = outerWheelRadius - valueSliderWidth; + colorWheelRadius = innerWheelRadius - innerPadding; + + outerWheelRect.set(centerX - outerWheelRadius, centerY - outerWheelRadius, centerX + outerWheelRadius, centerY + outerWheelRadius); + innerWheelRect.set(centerX - innerWheelRadius, centerY - innerWheelRadius, centerX + innerWheelRadius, centerY + innerWheelRadius); + + colorWheelBitmap = createColorWheelBitmap(colorWheelRadius * 2, colorWheelRadius * 2); + + gradientRotationMatrix = new Matrix(); + gradientRotationMatrix.preRotate(270, width / 2, height / 2); + + valueSliderPath.arcTo(outerWheelRect, 270, 180); + valueSliderPath.arcTo(innerWheelRect, 90, -180); + + } + + private Bitmap createColorWheelBitmap(int width, int height) { + + Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); + + int colorCount = 12; + int colorAngleStep = 360 / 12; + int colors[] = new int[colorCount + 1]; + float hsv[] = new float[] { 0f, 1f, 1f }; + for (int i = 0; i < colors.length; i++) { + hsv[0] = (i * colorAngleStep + 180) % 360; + colors[i] = Color.HSVToColor(hsv); + } + colors[colorCount] = colors[0]; + + SweepGradient sweepGradient = new SweepGradient(width / 2, height / 2, colors, null); + RadialGradient radialGradient = new RadialGradient(width / 2, height / 2, colorWheelRadius, 0xFFFFFFFF, 0x00FFFFFF, TileMode.CLAMP); + ComposeShader composeShader = new ComposeShader(sweepGradient, radialGradient, PorterDuff.Mode.SRC_OVER); + + colorWheelPaint.setShader(composeShader); + + Canvas canvas = new Canvas(bitmap); + canvas.drawCircle(width / 2, height / 2, colorWheelRadius, colorWheelPaint); + + return bitmap; + + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + + int x = (int) event.getX(); + int y = (int) event.getY(); + int cx = x - getWidth() / 2; + int cy = y - getHeight() / 2; + double d = Math.sqrt(cx * cx + cy * cy); + + if (d <= colorWheelRadius) { + + colorHSV[0] = (float) (Math.toDegrees(Math.atan2(cy, cx)) + 180f); + colorHSV[1] = Math.max(0f, Math.min(1f, (float) (d / colorWheelRadius))); + + updateAdjacentHue(); + invalidate(); + + } else if (x >= getWidth() / 2 && d >= innerWheelRadius) { + + colorHSV[2] = (float) Math.max(0, Math.min(1, Math.atan2(cy, cx) / Math.PI + 0.5f)); + + updateAdjacentHue(); + invalidate(); + + } + + return true; + } + return super.onTouchEvent(event); + } + + private void updateAdjacentHue() { + + for (int i = 0; i < paramColorCount; i++) { + adjacentHue[i] = (colorHSV[0] - paramHueSpreadAngle * (paramColorCount / 2 - i)) % 360.0f; + adjacentHue[i] = (adjacentHue[i] < 0) ? adjacentHue[i] + 360f : adjacentHue[i]; + } + adjacentHue[paramColorCount / 2] = colorHSV[0]; + + } + + public void setColor(int color) { + Color.colorToHSV(color, colorHSV); + updateAdjacentHue(); + } + + public int getColor() { + return Color.HSVToColor(colorHSV); + } + + public int[] getColors() { + int[] colors = new int[paramColorCount]; + float[] hsv = new float[3]; + for (int i = 0; i < paramColorCount; i++) { + hsv[0] = adjacentHue[i]; + hsv[1] = colorHSV[1]; + hsv[2] = colorHSV[2]; + colors[i] = Color.HSVToColor(hsv); + } + return colors; + } + + @Override + protected Parcelable onSaveInstanceState() { + Bundle state = new Bundle(); + state.putFloatArray("color", colorHSV); + state.putParcelable("super", super.onSaveInstanceState()); + return state; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + colorHSV = bundle.getFloatArray("color"); + updateAdjacentHue(); + super.onRestoreInstanceState(bundle.getParcelable("super")); + } else { + super.onRestoreInstanceState(state); + } + } + +} diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..236bff558af07faa3921ba35e2515edf62d04bb9 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0y~yVBle3U@+ofV_;y&V70PhU|?V=cJd72;Nak>;YjIV zU|`@Z@Q5sCVBqcqVMg*i978H@y@}M#x$Pk0_l;R9=s}}y)Bz@;fDIlu z9k|Rg7wSq%XnGv*cyVgk!An!8@u)0dUdSzR(?MN#$;6-wo~F4=rpypgS&(wy_rB-y z%Rg)0ox9gC|I3pTcKfT}|Jhf5fA%b=8s< z@rP6GpM8}0b@q8pxzP^>-qV|By+8Sh@4?G@S%yo?o4ijOElE0feC?BU?$4QHzAfMv zZnIkvw)$bw&Y0(Mtq-2)>8)Roe!kh6LKlwY3Iid9D z1OuNbC*JeuHQ7yjDlB#3AYc7-i?mdZ56Vp(wbL)g9s11qMSTmmtcKq-k#yGtcb=5? zWTxh|c3<|I^CWydx@zwh9?2rr*2lh#VZsdyOJ5kju>7LUyfa^ldydP2lZV1ZZ}}GN zI~ls#;)YQ2J%{Z-P4kSGS2L{9lQ!&sy6#pdxGi73p95=6=A4bzIKDh zOlGFti!AM!IP`hB4KFZg=g3IqaL+t+>;gC2gzoDnPR9TE>9n(!sg~vLr8)LTj!Zmw zOv=p9vTpKr*MIjncwN10H9t%JS=TDJ=WJO9+cx^zNoQ_nov?gWZ20rwU`~m7TKk=K zW%XjS%*CC2*E@J`_e_iNU==NnnrhIx(zrQxW|?&5L`(e`wS2Q(7e3vb>K2`88tlJR zd?xFK%XYhG?KYjh>+Ga8N$QVmHE++nkm;jTcI){qxuSJbFRFPx6;b_s?2&nYqCasb9(E2IwmSu49Le`>9l9y{dtO|T*ZFm-b(`3mN{%3n6{@*fMdgH2n^;##6 zgoP6=cm7`YB4=*HKA{^8%*uO|%kBvOu@gIxruBAX{e<|#S1#0C>TX!SEUxIs&QsM> z()K^fc;)|ojmg(d3-c#-{>pzPd%mTL^SP7Ip5*xSCHMHYy_mo~S?0IRgRfOa$2X;) zzI);O%M!8l#l_JK|7Z2?>d5`P^Mh^Vy8410^R|hCQo6{b*?+_m7*0>pJJ8nuMxKFz Ofx*+&&t;ucLK6UpJGVRl literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_drawer.png b/app/src/main/res/drawable-hdpi/ic_drawer.png new file mode 100644 index 0000000000000000000000000000000000000000..c59f601ca31dae344d0dc95912713ce54a8fbefe GIT binary patch literal 2829 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..36b4a5dd788084dc86f4af4bbff557cac1324242 GIT binary patch literal 7366 zcmeAS@N?(olHy`uVBq!ia0y~yVDJE84mJh`hS0a0-5D5UdOcknLn>~)z0DbOy|iY_8L!Qo&Rk2LIdf|2 z&I1jLjI^Kp`&aMq`G@`YGS^R2p5LqMKmOYAg>&8hk0+o1j&|tn`F9Tr`*Rus*Pjck zSDUxN>FCV8zqr)1lDT(RZJrgocWPDNt%cv#-&^~2{XOr!>mDwZyTsYVx0-b`f9xZ^ zmw)d3pQ^z+{{&m;{O2uKVxHv0-#KNq^^4T!V@15&t5<%NGBXQ~HkC06IG_DzWAy2x zaj!~s`PsMD>~WX9%K2sfDrUdA0o>trm(>L3SRa@8ARXva2QPo4|!-?G0siEL-L`@V)$Du}Jj63_XVVuUmdZ=^x3ARXCU7s{6e3 z(NpoQO5zSTf7`RURkmE*zNPc%tn!JUBP*quKVRhu2?)Ky#1!RW(Y?~jlzTNt#@*Tl zzv>xpxm)B1ycf8@&ho{O@o#g3pU}DTUk-Dwb{9^}y6F8b?kfA~29JZD?`f4lX{ zyHfAY|2Db9$F!?1;`si*3;hbd3p4$i)UZ!+f&3SxIm&a?_Oh&PQ&_HN&4eu1gtLZ8!owY@j*nELnIC9||^U1HO6 zw)SOi{5C6LhfvSH{cq1#T$`c!ZC!Fie*DAeJ(o{Suf1^W{I3w*8`VzgfBL3f|0>V< zf{D>o_(CYtCBX}&&IWm}oeMs%3aO4&)jgOQ`F}an@(()KT?#v^JsiE=949Z_!T&|z z(%qleXXJj?H{Px}Te3#AN3L|=i_7O%od4Fi_m}Ll{_4N4IsZ>_%=zCPw`W11zGd}I zfs*I{zC4(w$g=&)!5x*B9M|=|KD<6Z$ys)}idy~4t1JJcEb+K_DnD?=U(UAPY7hQ~ zchh1M{{`JTv_`}3r0o5>fBD`U8&o;0uamg2`u*97e}7s2xi>#MPmFipBEj?*UoHh- z=T+RE|C-}@mx#HP>W(_Up7?r!g@2_Jy>GiWF0!vZsrho1;rrJwmR!<)6wS4jfs404 z!Q%VGjIMQtC0%O&MUTpt%P%XQeWkwV>V|vFSDdSO9nue1^WXXWLO&$Re%72t(bt=z z^Gq&(nWH{O-u1-~Gl949oD2V}Jec-tf&u3#`;T7XC7L#_7u8f{1RFUnwk~;ArgS$n z=3!0Px7I7~3%|e2Nx70=vR*O2?}e?zT;BJl9Lm-F`;2$~mpJ{d=HL3~P0NJON$;O0 zdjFM$uZ4PxL5�-$1*P_aE~z?>$=jPt)U5w&B07Z6{uH_4YV4ePCGWTj0G=C@RpH+DM4$HyCGJ*pm~MHU{OfP{|F1D$c3g2pB=QY_+>5Iw* zXB1@?8LbS_npp5CZ%Rxb=gW_Exha2R-J|!|EdF2N^WK~<_;>HoEBlfYiuRxDU;bT| z`*Pjm`cj#^oPRrh@88s}9sg+d*yDdTMZUE8aZ-2fvQJX2 z%US}sR_qKB^Y#BV_tCN`f9yBK|C?g@QmlE|ft&*_XWrN|E@LrmUhwZ`#hE2%e)%?B zJ)k*zSG8VMMfUBJLR(BX0)WAznHlcy}o z%e!_>@S62`+nw5YB{KIOFFiVe_v_q*`ZIYqOm6VZbze_QcDH<|R@& zoTth@gxnCAc2+_72H&Fi%d2Jg-U{w(UY2-H;PUIAeMZOU$!ydFt8=SA@@qWhrl+C#M*;{ptK@(@o3s4Nf}Q^rSy3 zI+eUe^p0Effz&HHJ9Gg`|zf{)yMj zx#pyn*;>}AA9>33{+Qm37_IJ89~!idKL3~>?4|eq&YBB(>ND7~w7>E^IXipW|Hg+e zMN?jFK2+W$yXW}r1I2Sp?;MXfGZupyUo1wovTL4 z`OBYfrD^=ExP4~czKs&m>+H){otAy3;{L;T%klhxxa74DEst@{Tde!gF+#58so^E2 zd2@R=G>AX-{n@jjux4nmj{<<9t|$moLKPa?nNPQ*UA_AM{n`J z{P+3V%v#5yyLE>udvAH~WvaaG{ky7b@>8YR8grj6|71RsdD}+eh{@@TxwDuYd$%{A zw}}4Hv$gTOM0Q26-QuUFR`x*Sofcy=z*w$@9dhlXSw{5M~P>H%6+{B9(H6_xv;2w%dpXX z{mgb^%=ed}JO2qE`Z>djZRfYc$!-Ud?@yaYAva6nBGmXeBf8cR=y}Wd=Ka5gVOfWHC_&^J>^XWbA*pPo|{?qOrc^A z_o8JL*;D#BZGRmy?b_RC#?7gI;ASLI-f}x3P#v7)C zODtnqedaJLidrP{xlBoE;%-vgp_I}j?WDd#xu%Kz(pe_1>Jrn(yRVvk=4h*4FIFFJ z@@cPR|Gxi*bJ9-p-gnHi@HMy}v^=2Z?U7{rDPkKRcR#w@{O;I}4uPj44IJ!thjRWZ zZcbBfS*AH-ndXTz;zGgl9m}g7ZO#fWS}7+mbBA+^k8fdf#wKZ%$?sI>zG!>U`Ho}m z6ULh^{4PG9oW7{!tIXUm%d9f3r~c0O^0*VadCvs+e#hzRgvUJDEZ-Zu;@7?%M?M&P z@ua{1F6>oe&t`Y+OUI_UMt_vHoQzZSD44Ev&b3D(U2##yETuOU9Gew2w3{|1C>^=O zf6%yAQFX_R!$nRi~8^^ZMg7TYK#_y?K0DE?4aDW+}P2{I^AB^XH$Q@~N8^ zPdvuq-qp|JDR;1=e6m7WAIHVboTujXb42SMT4OmOa)Y9Ax>MRQhZQU3ozj0OmCQQ7 zcUhHl+M`~B*7 z9H7s`y2LB*m|;JJp& zoLGjWoF5(A9x2^AB!6+UMTb$ca+VtRMdOH$g-Oee1xSWpFWoM?$|ZvCI!}0{w$_?Quz6_7n z{OH*HL@`fHyztq-j`=4Yn>0c@9vtN_PJ(Ot?h>bt^0X%mTcDF>Rl9Nbs@6Mc_ab-*Z7mgJY%3j4q`( zA+8%AXPoYETvskqWOHcZTP^2l#T=W`*p)BaaY$|xO1afBF;mrP+ER|2VvQ%}iFU|* zc6c(ARq4J@i<7Zom!{>xDKl9we(?xQm1{a`HgSGQde^z)B}dQhtJ^VM|7r8*HwWDB z>#6)(B0s%o*?{j^h^WVaVUqG|SyUbaPXnskVrzn32vl zp8dOTs@ndTSbnMQ&aJd~vv)@q&B#dkAbHoS@#uVmnBL#3WDDcBDSxZ5PTFT6^Yi_` zJNwS+ySx+vle_*MDlqun)Zk5>9iQGOJkfhyw$4Z22wZN39)}(o<8qcCn1$c%= zw7Vk$loKdMMb;8NP~ZBM zN_KJJJAqEF-yR{i+?+f^Z@VlyW+l|UX7Pq2YEq?Uh7pOv-B-62M)+IIeluyqRmHE@ zy664;|CXO^b_6G{)~-or#!4?wiTbrZv{Bbve%oP_ZErKjQ}K^=%q_opI4WHE|K;rs z+p@Is&CKNEd-wl6?s<5+e0`%oe|-!8H~C}MyZIj+*cQGq|8jRl=2f#j8-7TdXk1^s zFGti&^lD-)pW;%@jY^4j(_E(~c}5s!HFIwan9|PLBop#GeNorcKCSyAAyujiFWCxC zUH5Ut9N~7Y6WwjQ$4dGd5Y+vHX$ zH!HCpOBUTSmc07TGvdLlj#-wRD+;>~AG%o>@kF3K>bHf?#%^cXt#|a~v{#yzb>2vr z-*WcbTno*N0-xibHydxfZTb9KcAo1s{{MUReu!&_tjRfaazW5ak(iX_vUP9rH44jL z=W;$1OW!Sb=J}U|oU4b+H}5OFD){w;ar(I)+n+Z*9}B;)N&9!wyS>sqzG8Oyk5=YA z+h50@tj<0B?o#;l-1{4Mr@dY$8!BCH8@}t;-d|0k@p&iXF6~lWyR0s>7D-k$-~m^kKXdvEmAxod*O+Ge#l1d z1xZgAa(7Mb?EbfNV*h_#^9ACsBk$Vnud=N%d;M^$BY*$aUAxz5m#X$}o~?UIw^{mA zcyEnfcI(OFNN(S4Dp#V`^{p$26gQl|F)VD_&ahQ0V)W;2PqnnKKW+4XPHbt<8|Bk~ zHu!0b}dEhmFmi_OOG z9zRLwFP8hZQ{+KI_Ql@A`#$gfXB)7%zSrrf=Kj@5+6$7z7YnbN7+diy#$4Y2-)sB4 zTWe-M-s@O?J$bEM-s&$iHv6zISGC%Dw`rT)-;~YP_m|yO@{-;Y7-5y=>~Qi(?;NJf zp*??Ip1yl&t$C$5Ti(Z0-K)OqhU9&m5xxDQ=Gu3X&(}=fW|b~`3?Q_FX$?~;M@0o@3Y*TFY(FiKE>Zz_9>oWYQ1X6oJy9EF77>*g|_vF zy}o>lS!wrR)0~89uO93OV85*;yXLgX`<+k!ncR7ye{Y+`@~_q1)6T|~-JEf5+wQdf zn@@u>Hl5#`^2{-9>xTvBZ5}52w|-E*e=0|`{BE3RxoXIrr7T-IR=G{CzZ%}VX=?Mo z3$qJWXPcHsExCGAUttE9tj_5YgXzJoxu<*nIh%>@U$|=K{-4{r_A_eT%W{hH)6L9( zbiK-EBJ+*#EoV1tT~7>K$(N>T<)eS$ph|f4VUxFB|1S4kR;q|xz*X_D&Fcb#=zqy9 zWyQ75!sTDtBp#mp(|!HrsbXf`r?1R?x=UtETi;yR$0ux5A~Ac-UPH}yS!XVHT~@gz zzk;jA_qNU*=FkJ&0i4@{qc0x0|0i{G#_0#@RR)`5{_e=EoOMj|rd5ys^`w$bVuv4X zm5^9__1pB7OWpimt^U}ut^3kyk_WEI@xYy%thOPdZ?Z39mTv2+w z>G}_owP_*ZeSCixZ+#)^)|z4E#uBSr9aS)^dH=LkO?H=8s>nA^xS&(Ty~=ONf$)4& zwmm2QZ`mA|`JJ~)@7>(5nfr9Va%jG_)T-RyF=;z~m(F0k z@4n^nbiV}}%(IkkE#TVUa%@Afx|FluO?%ntyllU|J>4?(OIr3;{>OLN4=H3Z9Xy+m zogcM%>+?G|XYGy4$u*h2^s~t4Qn8Co*@uf+?RmrRy^s7DK6(D+IUnvQSiaxsSK)h2 zVds{N-4UC=KULWJ?5o1xv)h}$S_mZ_P+!Oj@a>Pvim@+dDZPEm{jm3|y~Nt`q^4kOW_$YLYHiY(TGF7!Ud=tK4eUPoj!()D# z-$b9!H&1TRUi3KgMfw-{%@@N9Eq<>$t+6fbw8*w~6Q_x<$!MDM;_Bpr86gZ0TM9}$ zlol*uclf2Zpo^ha{6Z1aEeD6MO3Y;f7vz|#dK>Od%d+Zg+49z2?3UJ#>~#VD1uqRH zp0nNBc#CCQ&RHe#zHckU-B+gxPngi)#JOBpSovN$qk2DFzpS}|R^cT?@+ z+$zsY+iL4CY@N`*XrE;3@;4u!bv9aBFP5Ladb3DjsiWe*TQf51b4!i#bpcS5Z99Gg_vQC&Uo2&5OI}kcAc<@i%G5OQ!u)5PTrQ67Jew>cIuq~&|~N>6@e$H2hA;OXk;vd$@?2>=ElC$<0p literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_action_settings.png b/app/src/main/res/drawable-mdpi/ic_action_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..c290e5902fd96e62a0a15c6a88d90c5d261b64b2 GIT binary patch literal 594 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}k|nMYCBgY=CFO}lsSJ)O z`AMk?p1FzXsX?iUDV2pMQ*9U+7{7SBIEGZ*dK0GTf7n4pPsi9)c(%gntagWArvK_IvgV^2&Q__AdWfvu~5_>l=a<;S%3J$nBDO!u7z0{YqZ2 z!@{)lyF_la&WOJ#@g!&Fr5_4^Lta$hyu*4x*5)zuzKjxqymO^GA;C)&4pg_)+QbVs zY&2ysI>&x54Jn2d(_Ok-s2r`ib1;qPvUc=<}%XuyRWJG@qWlGi6o79W4je9-iE9 zK^1Dd6a5YBvcs-NaUFL#c4Qfk{DYk~Pk7mXv&M7^aITy@;bV0)pU;+^{Ev+#E~+*? zU�%<@RZhPPZ#AnHvx0J6_V^<-9ccud&9be}%JO-?+RkeD-S#haY#>J!VQ!cHDI~ z*Q0IT|JVH*dM}%***9E>%6Y`KV3HS~-hL(?1|EggD?dLl?`2?MVDNPHb6Mw<&;$TQ C_X-05 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_drawer.png b/app/src/main/res/drawable-mdpi/ic_drawer.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed2c56ee4239ff2987568d4fdae10166650b120 GIT binary patch literal 2820 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 C*F3fW literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..9ce85cf764ebe7efa3380c89c8290e0da047b707 GIT binary patch literal 3876 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..fabe9d96563785c7d6b008bb3d8da25e816c343c GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0y~yVBlw9U~uAKV_;zD5a{{Az`(##?Bp53!NI{%!;#X# zz`(#+;1OBOz`)%J!i?r8Pp@TQUf1 zO@>Y7rMhp{x__!49~SL?aG;M@TkOmXgQN{(JaZG%Q-e|yQz{EjrrIztuoQZ_IEGZ*dK0A^AnhpP$IYSC#nF^#(af=E(ab~v zg%>`_-3yq!eOQ+-Due1a^;AELx7;Si1Er589uH?%+Gj~HrD1p+kLKVclGx2 z>g|6@?w|29y1707eeLgWe`CE={pZ*WNu_rHEs zJ$Y4`CaWF4w7-f;y7>W5!}C7ggtHCHUwvwfVNO^SGgW8lpC=3rL04rOt4hQ^XtCzM z^<;Ed9&cDsr<9v?_Ap=bmkEp_yBA$By`r)2FjwlGMgEWHq_i6zm{#(+m8rq{Z>QUn z4QeL)lv_SNXumD|?5TnIw7T^V-knxIU!?DGa^3^?MS=%Ge~LrZ_`(^+%T{5 zjPKI>uQgNoGyjUGGbk*yG^(|b%C%FB+Rn)y-u-ZIld7RbuZZA6*J_?iuZ$+MHava$ zl=)YLK|<=~T;cj&Hs)=P$(n8ZnF_XL-nn>d{gynh`|(n5wpJAvU)H|ERM5rCe9g?S z==>qhPn~4~PQBk$F8p$BKPbyQPi~6+mH@j`?0kx=XJ6i&%Fd9eu4&i*LS&c4PlZ1I z^12xTe>U{g_Ax!^UCj08^4_>cH3usX;oGe#E9HupN;I73Trh9K8_z_)2{LDA$ONzW z_=MR`bJqU_9smCXEH|n5G+M^BGg!(#(^%)(85*SEek{7W?$Pc-x9Qj4M1OXTM@Rtx>qSWa5)j;f9#2 zGELSD4;c8Dx-4Dd8Gip+NHLFS*w%dJ13gPWbqCF~aoe;>Q8)6@kxpR^=btj~%0z>w ztF(Ww(>(SGks_!&U-U|I8cGc8U+lnhj;=_mTURgU+-@s(A zJ>OWqww~;s`uWgehRB1ubC1n(^onX#-6AL(ChQlrPfqro?1LxwXRcBF*EiXqBksU7 z#_R^|!@ZOA8XoNW*ShH8K~dTEP2OQG70)yFm>c}I_nTDB+3Lo4Qt_DO&VWS4IY+)6 z+2?R&zi|9&MV@P3FK4afDOml%UMp4q$l{Zm<5F>#j5nt;>K z*1m6k#r}Zha?9a;+)rc8UD#MZ+VL?wknxqddgAKK`|jR3Glcuu74&D7@*H58=n#7G m(QWTKjuBBy{?hvLGUqJakmU0qqEPb}zQ?(1vl5e?Mg>EgP<{zP$6U-ROQ zu2a7sRxi%Jw&(k^v;VeUw|lQz`~GlIyvbvLx3(rf_nY4%M1;3f6T0AWQd-kD9X5C zB7=f(YKIF$hBd>Q^I=`C3=swlB5B@7EE#U-G8lMT#JFBV&*2Bohp{DjnN#sh3w(sdU6`)JjJy| z%o3RrXF2E{s+=il)M�PV*|l=S%D z)AOqf92giLmegJRr=!1Fs==DAA@|=R)pslzaoh_^zjvo?;&<4}u;Asb@XrOHuyI{D zVdu@8PoF%w;dR6*I`LF^?Z5Ox@dv{H=KQR)`SbnjgME)w8jWHb-C2G-ICSQV&r+H5 zlQ>(F?mX*v|FfO@{~y`QN=H1Cc1CE4JPs5p>~opb^Vw*rQm4}-&7-Q9{-->;uk)MP z?!GC*hAcbA>WR85Vw0J_d8-RVlpJ{Uoq^%g?)-ySG&qj}HTE=evN)dL5KdIQ z)xnt56`|b6AwIM9hvGpG7NKqxg_9j3flA&JO+5^QxN*)_l1-a!&&`e3ua#^+9GA!W47@5h1D7SxBBgz zj~g6#A;E5ZB*#GS*kPxQ7CM}hlTU9{TEnyYnAC=_HO#v^zb2pGSk5BU=z4(DjHTR3 zAyLlJBf=-b?}o<;1sN3+!CRc>oXjnOht!oOukhZYwoCBm5s4%t!}bUd9p!66{lfYJ z)g8`9%vFRsosHCYPGIufxFqC~&?UD^c|poAbym(c@sLuUeDYRG_9k}ADLM+;Ct9D( zeRBAT@e}DMil3sn<|a85F8LAsNF(S}mY3vHfu|-<*-~d1IfgEt6?AvS!Vp2z{wSxl z3%3QW4{To{Y*ISQ@@%u1r}xsei>6+d$`H@^p1J--$u7aWQ|0`oUkJZ+`lb7e=`WbS zl=JYmi8deaNY{{@Ex|64E?F+IeumF7$;;i6$3qOv4PVcAK9hfDerSZ&Hmw@biKn=x zdQDZEDy^j-vU1h3RrgkLhkgz{9n!xtF1U7`Tc~mHe>d_u9`{m@QFl-8KgT-vdGO8PyUV$j zi}~7GeO;%wDtoE)!rd*_s-Zv4yNvdDMa_T;rjSw=362#t!}?6!99TGea2*X~{}xO}JIWWUw(uB9K| z@NwJ8Z7a7+Zg_fw?e@BDx!Y zH{DKew)C;PC-y$^D*0L%`>^WL*SWJd&pz~a#qIU)%-&_bYrix9jLCe>d6CA&7Y?6r zeh~QdqCNNgsRr5i*VOqt`!}Xte?weiF{Ks~WZOrc( z-HVJrV}4-!iS4KT59iN|Z@uqaulzsdf7Sns49go-8Pl0N8yy>?nSTGMs!`nEXK!^o z_1mVKZykFU>~s`$>~C7z^z`6b#f%egCahKb{(Q!{iRUu;S_A4{T)V)Y_$;yea2=0& zYkO;Wn|)tFM}*Wx!|A5w7w~uqa%k{cmrdoEZ^s;PjneQ^$Wq(XB zE%MCOh`AA-Io>jsdRptu@^bdw|MT{9`=hy!xF1)G&(J>+TTr?1+@UY6%f(je3F%l( zbMWc#vzYS1Q9x^jSdZ!_;d0eJuF6BQhtiewFPdHKxZxb5CFl3aL(8{n(wm8UOe9?^Mp05k-A*loR+-^iPE^P#l9&$H9T$q+0Ijz(^k*ZKKu5}=2N#P zn9q4X|NmQ|LqZQHZCl#r9j+@I@oev!EXz$cg_XCt9*eSSw}r8-vDwkJO)K}R|LV8l z)7RDQRjcyNZj3v4s_EcX#_ZSJpLO=5U*2G_JbEWM>JG<72+!miM zT7N_1PQ_E{_WV=(XWp5zW##H4J5$c5T}pfT?4IttXufHyrazm`m&bea))wCTVO!pQ z{pNaGfBIRC+q;{$IqzJ&-)6_2)a577owc?PSrYOkt)mB z$?2cY_spF-x3*62=bePxi?&riPd;})i$DMUE`gGVmt6mMKeygveJhIR>@!u2w#o?{vP3ODqSM8(!-MR7pPJPya z@&%tS-f{oV*4ljj-^8!|{LZZXGy6}s@wUC5XJKb)`N+QL@5?{SozJJ7SDPpPZ_&Tg z>%_(M>wa8)ef`|U85b8$|1^E_{@j|Se_tJVExG>ou|vn?_MNOSHjMic_WSL@@;l|S z?-$?a_kU8OP_OYna3$jP7}zo^M^L^0kQd!rh&g3=PQ#X1sn?!oc9r!BEr4$H2fLc%Zz2H)T=zB(_H? R2@DJj44$rjF6*2UngAQMK|lZi literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..fca8186f8c14d8024d8be2050e97679e168c0863 GIT binary patch literal 11861 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 R%fP_E;OXk;vd$@?2>=F56m$Rp literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b91e9d7f285e8110ba3ba4e72cc6f0416eb3a30a GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0y~yU=U+qU`XO%V_;wiVOM^`z`!6`;u=vBoS#-wo>-L1 z;Fyx1l&avFo0y&&l$w}QS$HzlhJk^h$kW9!B;(%O3yNG$j3O=@1JJNr0G;NdTDNjha#F?D7CbCDhSzT_&<2G$Qi^na>d^eKYb{(JaZG%Q-e|yQz{EjrrIztu)XwjaSW-r^(I!gK-yg-Zn?d&m}Y>(>W_^=oGc#3 zZblp(o{hXh30aK-!O|i}41%XkU=n5VxU%HHGA@o49k#`6FMV9OrbzC7;L*t9^lRQP zy}K*Qcd!0ydH3e~**7P?y>svF-uG{-^Y8BqZAmbY;9+Y%h)gM4n5{Cp@b>LnwVEwF z`tzM;$Hc~-J@qdxKFsAu=?{y@jkh^&Mc%ys*3nhX;qoH?kXG^4T#Rd*Jd&AexF-K$ z6Mk^;-*w&HlSg*LG*%{a5nxJSQh({EN*o zyfOVQZzbvg$0W^ zZ{A+{#QmGhqJ`%d$?v+qaKrg2i#TgSqnI>mY&O2>bE@x+@|UW9VAytC(s0VV+7}M5 z7~UCwQ{AjzBXl9d#81TUe8>;Mi7$*r{)*j7mbgFvL(lEmvuAt%__^?@Psf7)D@s@b z&g_4zQM2cGamIa?4&Hr-J~loO7I?s(VfaTz&~o*HY4;ZAtn8>g?cpv~cfN>iZIhfW zx1kEF#-rH7f)mzB=6xptM9>>b4_=~rGjs)_f{!+%s4cmW#*6dNe5jLjHASRM9$BjWGOkZ z)AGWM%_f(mF6?@IlIz*~L+u~-x;s9(;j^f_d`9#_)@u_RC;v;G8pC7dA#q&wEXP#m z{s&e)Z}T61&OUr1`+@h5eRDr7pXsnu`mWdYBQsT>ELkr0IO2OtJh(++?=@=YL*G4^A%D&oQx2 zS9_uL#OhL)rGA11zv7Yv7LQxgr_L9g6>{Lr1(g|nsdEZswl5UP2DP znIkXnOEq8);HZ{6zG=N@^%1V$^$WUhdAT#}EtvOgOJ>&bSs5AE-E;g7RWI84CMt2+ zgdK|+jE#60O;ST|Nqb6t4NE^1v&CP_F_1IgXLr)7%^W}Sk1Kjq2sr$(ZT5aD^T#K- zt1s7MLRWKX?PZlP_%VUXrngy^N9yPcSzJUH?`FHxBiSwS+DZr)|Blh=RfcZX`fR#|4gf2 za`uxuyHzTthj>H@U7q5zNb^!r+4DUU#pNAVvd%szvuN$KZ~5J)1aBamX zt0sMW*^;~MO_qyOZ`hoLo(HP+&8~U=IDTlI(D~cnmYA#ad^2F&eM4w<_=(z0D=mZ{ zd@ld-xBB6JJCXF8=Rfp(pY%c5`>p)6J_Z)CwOqTI?oMg>9eib>Cuy63!AN>Xh9t-Pgu+d;NF zufyjXaer*}eeP6i;rCp);H&iH#YZGfCuDU*In~b4<7N9NaOv2-Cs$JP-N3u%iSMJ~ll-|;pylTZ%d5_@bUw-$wSub}vcI3f^@+j52BCl*4 zzWkinxZbfSKJ3|yRVp1OXAX-W?Ma@a?r^v(?e3xTM>5mHqP&l!&OK5inU$>eC0z8% z($-lgzwYCIE;)NkPvMr%9t#)W3`G_Tq3!P{aws2M&%E^Cy@2D!#~tS`*PrtDcT=7A zN!xe2jMw}AE>AVFo~n4@!G)I2x8gnx(lHz}3>e>S5PhUm5_om5LPJhPk@(jATE+^# zt_F;v#?F_u_C#F$$IR{{_~M(CfvD~JroZW!waj9LKgtIfZV0^CI?LDQE&~GtgQu&X J%Q~loCID^7WE21Z literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_drawer.png b/app/src/main/res/drawable-xxhdpi/ic_drawer.png new file mode 100644 index 0000000000000000000000000000000000000000..9c4685d6e046ce6c450c19426dce627a88718bfc GIT binary patch literal 202 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/dimme.xml b/app/src/main/res/drawable/dimme.xml new file mode 100644 index 0000000..dbc433c --- /dev/null +++ b/app/src/main/res/drawable/dimme.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/main/res/layout/act_demo.xml b/app/src/main/res/layout/act_demo.xml new file mode 100644 index 0000000..31ed633 --- /dev/null +++ b/app/src/main/res/layout/act_demo.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/act_multi_picker.xml b/app/src/main/res/layout/act_multi_picker.xml new file mode 100644 index 0000000..d064d56 --- /dev/null +++ b/app/src/main/res/layout/act_multi_picker.xml @@ -0,0 +1,21 @@ + + + + +