├── .gitignore ├── README.md ├── art ├── google-play-badge.png ├── hall_scheme_1.png └── hall_scheme_1_zoom.png ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── fonts │ │ └── Roboto-Medium.ttf │ ├── java │ └── by │ │ └── anatoldeveloper │ │ └── hallscheme │ │ ├── hall │ │ ├── HallScheme.java │ │ ├── ImageClickListener.java │ │ ├── MaxSeatsClickListener.java │ │ ├── ScenePosition.java │ │ ├── Seat.java │ │ ├── SeatListener.java │ │ ├── Zone.java │ │ └── ZoneListener.java │ │ └── view │ │ └── ZoomableImageView.java │ └── res │ └── values │ ├── attrs.xml │ ├── colors.xml │ └── strings.xml ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── fonts │ │ └── DroidSansMono.ttf │ ├── java │ └── by │ │ └── anatoldeveloper │ │ └── hallscheme │ │ └── example │ │ ├── MainActivity.java │ │ ├── SeatExample.java │ │ ├── ZoneExample.java │ │ └── schemes │ │ ├── SchemeBasic.java │ │ ├── SchemeCustomTypeface.java │ │ ├── SchemeDarkTheme.java │ │ ├── SchemeMaxSelectedSeats.java │ │ ├── SchemeWithMarkers.java │ │ ├── SchemeWithScene.java │ │ └── SchemeWithZones.java │ └── res │ ├── layout │ ├── activity_main.xml │ ├── basic_scheme_fragment.xml │ ├── halls_fragment.xml │ └── scheme_with_button.xml │ ├── menu │ └── main_menu.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # IntelliJ IDEA 19 | .idea/ 20 | *.iml 21 | *.iws 22 | *.ipr 23 | 24 | # Gradle 25 | .gradle 26 | build/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HallScheme 2 | ==================== 3 | 4 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-HallScheme-green.svg?style=true)](https://android-arsenal.com/details/1/2935) 5 | 6 | ### Description 7 | 8 | HallScheme is a lightweight simple library for creating rectangle halls. 9 | 10 | ![Alt text](/art/hall_scheme_1.png?raw=true) 11 | 12 | ![Alt text](/art/hall_scheme_1_zoom.png?raw=true) 13 | 14 | ### Demo 15 | 16 | [![HallScheme Demo on Google Play Store](/art/google-play-badge.png?raw=true)](https://play.google.com/store/apps/details?id=by.anatoldeveloper.hallscheme.example) 17 | 18 | ### Integration 19 | 20 | **1)** Add as a dependency to your ``build.gradle``: 21 | 22 | ```groovy 23 | dependencies { 24 | compile 'com.github.Nublo:hallscheme:1.1.1' 25 | } 26 | ``` 27 | 28 | **2)** Add ``by.anatoldeveloper.ZoomableImage`` to your layout XML file. Content is automatically centered within free space. 29 | 30 | ```xml 31 | 35 | 36 | 40 | 41 | 42 | ``` 43 | 44 | **3)** Customize `Seat` interface: 45 | 46 | ``` 47 | public class SeatExample implements Seat { 48 | 49 | public int id; 50 | public int color = Color.RED; 51 | public String marker; 52 | public String selectedSeatMarker; 53 | public HallScheme.SeatStatus status; 54 | 55 | @Override 56 | public int id() { 57 | return id; 58 | } 59 | 60 | @Override 61 | public int color() { 62 | return color; 63 | } 64 | 65 | @Override 66 | public String marker() { 67 | return marker; 68 | } 69 | 70 | @Override 71 | public String selectedSeat() { 72 | return selectedSeatMarker; 73 | } 74 | 75 | @Override 76 | public HallScheme.SeatStatus status() { 77 | return status; 78 | } 79 | 80 | @Override 81 | public void setStatus(HallScheme.SeatStatus status) { 82 | this.status = status; 83 | } 84 | 85 | } 86 | ``` 87 | 88 | **4)** Attach ZoomableImage to `HallScheme` and add a 2-dimesional `Seat` array: 89 | 90 | ``` 91 | ZoomableImageView imageView = (ZoomableImageView) rootView.findViewById(R.id.zoomable_image); 92 | Seat seats[][] = new Seat[10][10]; 93 | HallScheme scheme = new HallScheme(imageView, seats, getActivity()); 94 | ``` 95 | 96 | **5)** Set `SeatListener` to `HallScheme` to handle click events on seats: 97 | 98 | ``` 99 | scheme.setSeatListener(new SeatListener() { 100 | 101 | @Override 102 | public void selectSeat(int id) { 103 | Toast.makeText(getActivity(), "select seat " + id, Toast.LENGTH_SHORT).show(); 104 | } 105 | 106 | @Override 107 | public void unSelectSeat(int id) { 108 | Toast.makeText(getActivity(), "unSelect seat " + id, Toast.LENGTH_SHORT).show(); 109 | } 110 | 111 | }); 112 | ``` 113 | 114 | ### Seat interface 115 | To use the library you should implement custom `Seat`. It has the following methods: 116 | 117 | **a)** `int id()` should return current `id` for current `Seat`. It will also be later returned when you attach `SeatListener` for scheme. 118 | 119 | **b)** `int color()` should return the color of the checked `Seat`. 120 | 121 | **c)** `String marker()` should return text representation for empty `Seat`. For example you can use it to see row and column. 122 | 123 | **d)** `String selectedSeat();` should return `Seat` number when the `Seat` is checked. 124 | 125 | **e)** `HallScheme.SeatStatus status();` should return current state of the `Seat`. The following statuses are supported: 126 | 127 | + `FREE` - seat is free and can be checked; 128 | + `CHOSEN` - seat is chosen and can be unchecked; 129 | + `BUSY` - seat cannot be used; 130 | + `INFO` - the seat is empty, but you can use to show some text there; 131 | + `EMPTY` - the seat is empty. 132 | 133 | **f)** `void setStatus(HallScheme.SeatStatus status);` update current `Seat` status. 134 | 135 | ### Features: 136 | 137 | **a)** Zoomable image. 138 | 139 | Zooming can be enabled/disabled either from code: 140 | 141 | `imageView.setZoomByDoubleTap(false);` 142 | 143 | or from xml: 144 | 145 | 146 | 152 | 153 | 158 | 159 | 160 | **b)** Fling while touching image. 161 | 162 | **c)** Smooth animation available either on double tap or on gesture move. 163 | 164 | **d)** Showing scheme scene from any of 4 sides. 165 | 166 | `hallScheme.setScenePosition(ScenePosition.NORTH);` 167 | 168 | + `NORTH` 169 | + `SOUTH` 170 | + `EAST` 171 | + `WEST` 172 | 173 | **e)** Adding text to show row or hall numbers. 174 | 175 | **f)** Handling clicking on seats on your scheme. 176 | 177 | **g)** Full customization for drawing: 178 | 179 | + Setting background color for scheme: 180 | 181 | ```java 182 | scheme.setBackgroundColor(Color.RED); 183 | ``` 184 | + Setting color for `BUSY` seats: 185 | 186 | ```java 187 | scheme.setUnavailableSeatBackgroundColor(Color.RED); 188 | ``` 189 | + Setting background color for `CHOSEN` seats: 190 | 191 | ```java 192 | scheme.setChosenSeatBackgroundColor(Color.RED); 193 | ``` 194 | + Setting text color for `CHOSEN` seats: 195 | 196 | ```java 197 | scheme.setChosenSeatTextColor(Color.RED); 198 | ``` 199 | + Setting color for `INFO` seats: 200 | 201 | ```java 202 | scheme.setMarkerColor(Color.RED); 203 | ``` 204 | + Setting text color for Scene: 205 | 206 | ```java 207 | scheme.setScenePaintColor(Color.RED); 208 | ``` 209 | + Setting background color for Scene: 210 | 211 | ```java 212 | scheme.setSceneBackgroundColor(Color.RED); 213 | ``` 214 | + Setting custom typeface for Scene: 215 | 216 | ```java 217 | scheme.setTypeface(typeface); 218 | ``` 219 | 220 | **h)** Setting custom name for scene: 221 | 222 | scheme.setSceneName("Custom name"); 223 | 224 | **i)** Setting limit of checked seats and set listener for this event: 225 | 226 | scheme.setMaxSelectedSeats(4); 227 | scheme.setMaxSeatsClickListener(new MaxSeatsClickListener() { 228 | @Override 229 | public void maxSeatsReached(int id) { 230 | // Do something 231 | } 232 | }); 233 | 234 | By default it is unlimitted. So user can check as many seats as he wants. 235 | 236 | **j)** Programmatically click on scheme: 237 | 238 | scheme.clickSchemeProgrammatically(3, 4); 239 | 240 | So if seat was checked it becomes unchecked and `Seatlistener` will be notified. 241 | If seat was unchecked and limit is not reached seat becomes checked and `SeatListener` will be notified, otherway(when limit reached) seat will not be checked and `MaxSeatsListener` will be notified. 242 | 243 | **k)** Adding seat areas. 244 | 245 | Seat area will be drawn like a solid rectangle on scene and can have size from 1x1 block to all scheme. When user is clicking on seat area listener will be notified. Clicking on seat area is not counting in `maxSelectedSeats`. 246 | 247 | You can see how to use seat areas in examples. Main principle like with seats. You should set left top corner, width, height and color. Name for seat area is not used in current library implementation. 248 | 249 | 250 | ### Restrictions 251 | 252 | Image is currently drawing on standart `Bitmap`. Maximum size of `Bitmap` depends on underlying OpenGL implementation and it varies depending on device. It shouldn't be less then `2048x2048`. With current implementation your hall dimension(either rows or columns) shouldn't be more then `58`. Maximum scheme that can be drawn is `58x58`. Of course, if you know that devices using your app will have bigger maximum size - you can draw larger schemes. 253 | 254 | ### ChangeLog 255 | 256 | **Version 1.1.1:** 257 | 258 | + Remove dependency from appcompat library 259 | 260 | **Version 1.1.0:** 261 | 262 | + Ability to set custom typeface 263 | + Disable zooming by double tap 264 | + Programmatically click seat on scheme 265 | + Limiting checked seats 266 | + Added seat areas 267 | 268 | ### License 269 | 270 | ``` 271 | The MIT License (MIT) 272 | 273 | Copyright (c) 2016 Varyvonchyk Anatol 274 | 275 | Permission is hereby granted, free of charge, to any person obtaining a copy 276 | of this software and associated documentation files (the "Software"), to deal 277 | in the Software without restriction, including without limitation the rights 278 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 279 | copies of the Software, and to permit persons to whom the Software is 280 | furnished to do so, subject to the following conditions: 281 | 282 | The above copyright notice and this permission notice shall be included in all 283 | copies or substantial portions of the Software. 284 | 285 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 286 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 287 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 288 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 289 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 290 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 291 | SOFTWARE. 292 | ``` -------------------------------------------------------------------------------- /art/google-play-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nublo/HallScheme/7ac4bf085dae23c14d0b40c70e61d2f0e43a1bbb/art/google-play-badge.png -------------------------------------------------------------------------------- /art/hall_scheme_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nublo/HallScheme/7ac4bf085dae23c14d0b40c70e61d2f0e43a1bbb/art/hall_scheme_1.png -------------------------------------------------------------------------------- /art/hall_scheme_1_zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nublo/HallScheme/7ac4bf085dae23c14d0b40c70e61d2f0e43a1bbb/art/hall_scheme_1_zoom.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | VERSION_NAME=1.1.1 21 | VERSION_CODE=3 22 | GROUP=com.github.Nublo 23 | 24 | POM_DESCRIPTION=Simple Library for creating rectangle halls 25 | POM_URL=https://github.com/Nublo/HallScheme 26 | POM_SCM_URL=https://github.com/Nublo/HallScheme 27 | POM_SCM_CONNECTION=scm:git@github.com:Nublo/HallScheme.git 28 | POM_SCM_DEV_CONNECTION=scm:git@github.com:Nublo/HallScheme.git 29 | POM_LICENCE_NAME=The MIT License (MIT) 30 | POM_LICENCE_URL=https://opensource.org/licenses/MIT 31 | POM_LICENCE_DIST=repo 32 | POM_DEVELOPER_ID=Nublo 33 | POM_DEVELOPER_NAME=Varyvonchyk Anatol -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nublo/HallScheme/7ac4bf085dae23c14d0b40c70e61d2f0e43a1bbb/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 28 19:41:59 MSK 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.2.1-all.zip -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle' 3 | 4 | android { 5 | compileSdkVersion 25 6 | buildToolsVersion "25.0.1" 7 | 8 | defaultConfig { 9 | minSdkVersion 14 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /library/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=HallScheme 2 | POM_ARTIFACT_ID=hallscheme 3 | POM_PACKAGING=aar -------------------------------------------------------------------------------- /library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /library/src/main/assets/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nublo/HallScheme/7ac4bf085dae23c14d0b40c70e61d2f0e43a1bbb/library/src/main/assets/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /library/src/main/java/by/anatoldeveloper/hallscheme/hall/HallScheme.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.hall; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Point; 9 | import android.graphics.Rect; 10 | import android.graphics.Typeface; 11 | import android.os.Build; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | import by.anatoldeveloper.hallscheme.R; 17 | import by.anatoldeveloper.hallscheme.view.ZoomableImageView; 18 | 19 | /** 20 | * Created by Nublo on 28.10.2015. 21 | * Copyright Nublo 22 | */ 23 | public class HallScheme { 24 | 25 | private int width, height; 26 | private Seat[][] seats; 27 | 28 | private final Rect textBounds = new Rect(); 29 | private Paint textPaint, backgroundPaint, markerPaint, scenePaint; 30 | private int seatWidth, seatGap, offset; 31 | private int schemeBackgroundColor, unavailableSeatColor, chosenColor, sceneBackgroundColor; 32 | private int selectedSeats, maxSelectedSeats; 33 | private Typeface typeface; 34 | private String sceneName; 35 | 36 | private Scene scene; 37 | private ZoomableImageView image; 38 | private SeatListener listener; 39 | private MaxSeatsClickListener maxSeatsClickListener; 40 | private List zones; 41 | private ZoneListener zoneListener; 42 | 43 | public HallScheme(ZoomableImageView image, Seat[][] seats, Context context) { 44 | this.selectedSeats = 0; 45 | this.maxSelectedSeats = -1; 46 | this.image = image; 47 | this.seats = seats; 48 | nullifyMap(); 49 | 50 | image.setClickListener(new ImageClickListener() { 51 | @Override 52 | public void onClick(Point p) { 53 | p.x -= scene.getLeftYOffset(); 54 | p.y -= scene.getTopXOffset(); 55 | clickScheme(p); 56 | } 57 | }); 58 | 59 | typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Medium.ttf"); 60 | sceneName = context.getString(R.string.scene); 61 | 62 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 63 | schemeBackgroundColor = context.getResources().getColor(R.color.light_grey); 64 | unavailableSeatColor = context.getResources().getColor(R.color.disabled_color); 65 | chosenColor = context.getResources().getColor(R.color.orange); 66 | markerPaint = initTextPaint(context.getResources().getColor(R.color.black_gray)); 67 | scenePaint = initTextPaint(context.getResources().getColor(R.color.black_gray)); 68 | } else { 69 | schemeBackgroundColor = context.getColor(R.color.light_grey); 70 | unavailableSeatColor = context.getColor(R.color.disabled_color); 71 | chosenColor = context.getColor(R.color.orange); 72 | markerPaint = initTextPaint(context.getColor(R.color.black_gray)); 73 | scenePaint = initTextPaint(context.getColor(R.color.black_gray)); 74 | } 75 | sceneBackgroundColor = unavailableSeatColor; 76 | textPaint = initTextPaint(Color.WHITE); 77 | scenePaint.setTextSize(35); 78 | 79 | backgroundPaint = new Paint(); 80 | backgroundPaint.setStyle(Paint.Style.FILL); 81 | backgroundPaint.setColor(schemeBackgroundColor); 82 | backgroundPaint.setStrokeWidth(0); 83 | 84 | seatWidth = 30; 85 | seatGap = 5; 86 | offset = 30; 87 | height = seats.length; 88 | width = seats[0].length; 89 | this.scene = new Scene(ScenePosition.NONE, 0, 0, offset/2); 90 | image.setImageBitmap(getImageBitmap()); 91 | } 92 | 93 | public void setScenePosition(ScenePosition position) { 94 | scene = new Scene(position, width, height, offset/2); 95 | image.setImageBitmap(getImageBitmap()); 96 | } 97 | 98 | public void setSceneName(String name) { 99 | sceneName = name; 100 | image.setImageBitmap(getImageBitmap()); 101 | } 102 | 103 | public void setBackgroundColor(int color) { 104 | schemeBackgroundColor = color; 105 | image.setImageBitmap(getImageBitmap()); 106 | } 107 | 108 | public void setUnavailableSeatBackgroundColor(int color) { 109 | unavailableSeatColor = color; 110 | image.setImageBitmap(getImageBitmap()); 111 | } 112 | 113 | public void setChosenSeatTextColor(int color) { 114 | textPaint.setColor(color); 115 | image.setImageBitmap(getImageBitmap()); 116 | } 117 | 118 | public void setChosenSeatBackgroundColor(int color) { 119 | chosenColor = color; 120 | image.setImageBitmap(getImageBitmap()); 121 | } 122 | 123 | public void setMarkerColor(int color) { 124 | markerPaint.setColor(color); 125 | image.setImageBitmap(getImageBitmap()); 126 | } 127 | 128 | public void setSceneTextColor(int color) { 129 | scenePaint.setColor(color); 130 | image.setImageBitmap(getImageBitmap()); 131 | } 132 | 133 | public void setSceneBackgroundColor(int color) { 134 | sceneBackgroundColor = color; 135 | image.setImageBitmap(getImageBitmap()); 136 | } 137 | 138 | public void setMaxSelectedSeats(int maxSelectedSeats) { 139 | this.maxSelectedSeats = maxSelectedSeats; 140 | } 141 | 142 | public void setSeatListener(SeatListener listener) { 143 | this.listener = listener; 144 | } 145 | 146 | public void setMaxSeatsClickListener(MaxSeatsClickListener maxSeatsClickListener) { 147 | this.maxSeatsClickListener = maxSeatsClickListener; 148 | } 149 | 150 | /** 151 | * Set custom typeface to scheme. 152 | * Be careful when using. Bold typefaces can be drawn incorrectly. 153 | * @param typeface - Typeface to be setted 154 | */ 155 | public void setTypeface(Typeface typeface) { 156 | this.typeface = typeface; 157 | markerPaint.setTypeface(typeface); 158 | scenePaint.setTypeface(typeface); 159 | textPaint.setTypeface(typeface); 160 | image.setImageBitmap(getImageBitmap()); 161 | } 162 | 163 | public void setZones(List zones) { 164 | this.zones = zones; 165 | image.setImageBitmap(getImageBitmap()); 166 | } 167 | 168 | public void setZoneListener(ZoneListener zoneListener) { 169 | this.zoneListener = zoneListener; 170 | } 171 | 172 | private Paint initTextPaint(int color) { 173 | Paint paint = new Paint(); 174 | paint.setColor(color); 175 | paint.setStyle(Paint.Style.FILL); 176 | paint.setStrokeMiter(0); 177 | paint.setTextSize(25); 178 | paint.setTypeface(typeface); 179 | return paint; 180 | } 181 | 182 | private void clickScheme(Point point) { 183 | if (findZoneClick(point)) 184 | return; 185 | Point p = new Point(point.x - offset/2, point.y - offset/2); 186 | int row = p.x / (seatWidth + seatGap); 187 | int seat = p.y / (seatWidth + seatGap); 188 | if (canSeatPress(p, row, seat)) { 189 | clickScheme(row, seat); 190 | } 191 | } 192 | 193 | public boolean findZoneClick(Point p) { 194 | for (Zone zone : zones) { 195 | int topX = offset/2 + zone.leftTopX() * (seatWidth + seatGap); 196 | int topY = offset/2 + zone.leftTopY() * (seatWidth + seatGap); 197 | int bottomX = offset/2 + (zone.leftTopX() + zone.width()) * (seatWidth + seatGap) - seatGap; 198 | int bottomY = offset/2 + (zone.leftTopY() + zone.height()) * (seatWidth + seatGap) - seatGap; 199 | if (p.x >= topX && p.x <= bottomX && p.y >= topY && p.y <= bottomY) { 200 | if (zoneListener != null) 201 | zoneListener.zoneClick(zone.id()); 202 | return true; 203 | } 204 | } 205 | return false; 206 | } 207 | 208 | public void clickSchemeProgrammatically(int row, int seat) { 209 | if (SeatStatus.canSeatBePressed(seats[row][seat].status())) { 210 | clickScheme(seat, row); 211 | } 212 | } 213 | 214 | private void clickScheme(int row, int seat) { 215 | Seat pressedSeat = seats[seat][row]; 216 | if (updateSelectedSeatCount(pressedSeat)) { 217 | notifySeatListener(pressedSeat); 218 | pressedSeat.setStatus(pressedSeat.status().pressSeat()); 219 | image.setImageBitmap(getImageBitmap()); 220 | } else if (maxSeatsClickListener != null) { 221 | maxSeatsClickListener.maxSeatsReached(pressedSeat.id()); 222 | } 223 | } 224 | 225 | /** 226 | * Increases or decreases current selected seats count 227 | * @param seat Seat that has been clicked 228 | * @return false If selected seats reached max limit, false otherwise 229 | */ 230 | public boolean updateSelectedSeatCount(Seat seat) { 231 | if (seat.status() == SeatStatus.FREE) { 232 | if (maxSelectedSeats == -1 || selectedSeats + 1 <= maxSelectedSeats) { 233 | selectedSeats++; 234 | } else if (selectedSeats + 1 > maxSelectedSeats) { 235 | return false; 236 | } 237 | return true; 238 | } 239 | selectedSeats--; 240 | return true; 241 | } 242 | 243 | public boolean canSeatPress(Point p, int row, int seat) { 244 | if (row >= width || (p.x % (seatWidth + seatGap) >= seatWidth) 245 | || p.x <= 0) { 246 | return false; 247 | } 248 | if (seat >= height || (p.y % (seatWidth + seatGap) >= seatWidth) 249 | || p.y <= 0) { 250 | return false; 251 | } 252 | return SeatStatus.canSeatBePressed(seats[seat][row].status()); 253 | } 254 | 255 | private Bitmap getImageBitmap() { 256 | int bitmapHeight = height * (seatWidth + seatGap) - seatGap + offset + scene.getTopXOffset() + scene.getBottomXOffset(); 257 | int bitmapWidth = width * (seatWidth + seatGap) - seatGap + offset + scene.getLeftYOffset() + scene.getRightYOffset(); 258 | 259 | Bitmap tempBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); 260 | Canvas tempCanvas = new Canvas(tempBitmap); 261 | backgroundPaint.setColor(schemeBackgroundColor); 262 | tempCanvas.drawRect(0, 0, bitmapWidth, bitmapHeight, backgroundPaint); 263 | 264 | for (int i = 0; i < height; i++) { 265 | for (int j = 0; j < width; j++) { 266 | if (seats[i][j].status() == SeatStatus.EMPTY) 267 | continue; 268 | if (seats[i][j].status() == SeatStatus.INFO) { 269 | drawTextCentred(tempCanvas, markerPaint, seats[i][j].marker(), 270 | offset / 2 + (seatWidth + seatGap) * j + seatWidth / 2 + scene.getLeftYOffset(), 271 | offset / 2 + (seatWidth + seatGap) * i + seatWidth / 2 + scene.getTopXOffset()); 272 | continue; 273 | } 274 | if (seats[i][j].status() == SeatStatus.BUSY) { 275 | backgroundPaint.setColor(unavailableSeatColor); 276 | } else if (seats[i][j].status() == SeatStatus.FREE) { 277 | backgroundPaint.setColor(seats[i][j].color()); 278 | } else if (seats[i][j].status() == SeatStatus.CHOSEN) { 279 | backgroundPaint.setColor(chosenColor); 280 | } 281 | tempCanvas.drawRect(offset/2 + (seatWidth + seatGap) * j + scene.getLeftYOffset(), 282 | offset/2 + (seatWidth + seatGap) * i + scene.getTopXOffset(), 283 | offset/2 + (seatWidth + seatGap) * j + seatWidth + scene.getLeftYOffset(), 284 | offset/2 + (seatWidth + seatGap) * i + seatWidth + scene.getTopXOffset(), 285 | backgroundPaint); 286 | if (seats[i][j].status() == SeatStatus.CHOSEN) { 287 | drawTextCentred(tempCanvas, textPaint, seats[i][j].selectedSeat(), 288 | offset / 2 + (seatWidth + seatGap) * j + seatWidth / 2 + scene.getLeftYOffset(), 289 | offset / 2 + (seatWidth + seatGap) * i + seatWidth / 2 + scene.getTopXOffset()); 290 | } 291 | } 292 | } 293 | 294 | for(Zone zone : zones) { 295 | if (zone.width() == 0 || zone.height() == 0 296 | || zone.leftTopX() + zone.width() > width 297 | || zone.leftTopY() + zone.height() > height) 298 | continue; 299 | backgroundPaint.setColor(zone.color()); 300 | int topX = offset/2 + zone.leftTopX() * (seatWidth + seatGap) + scene.getLeftYOffset(); 301 | int topY = offset/2 + zone.leftTopY() * (seatWidth + seatGap) + scene.getTopXOffset(); 302 | int bottomX = offset/2 + (zone.leftTopX() + zone.width()) * (seatWidth + seatGap) - seatGap + scene.getLeftYOffset(); 303 | int bottomY = offset/2 + (zone.leftTopY() + zone.height()) * (seatWidth + seatGap) - seatGap + scene.getTopXOffset(); 304 | tempCanvas.drawRect(topX, topY, bottomX, bottomY, backgroundPaint); 305 | } 306 | 307 | drawScene(tempCanvas); 308 | 309 | return tempBitmap; 310 | } 311 | 312 | private void drawScene(Canvas canvas) { 313 | if (scene.position == ScenePosition.NONE) { 314 | return; 315 | } 316 | backgroundPaint.setColor(sceneBackgroundColor); 317 | int topX=0, topY=0, bottomX=0, bottomY=0; 318 | if (scene.position == ScenePosition.NORTH) { 319 | int totalWidth = width * (seatWidth + seatGap) - seatGap + offset; 320 | topX = offset / 2; 321 | topY = totalWidth / 2 - width * 6; 322 | bottomX = topX + scene.dimension; 323 | bottomY = topY + scene.dimensionSecond; 324 | } 325 | if (scene.position == ScenePosition.SOUTH) { 326 | int totalWidth = width * (seatWidth + seatGap) - seatGap + offset; 327 | topX = height * (seatWidth + seatGap) - seatGap + offset; 328 | topY = totalWidth / 2 - width * 6; 329 | bottomX = topX + scene.dimension; 330 | bottomY = topY + scene.dimensionSecond; 331 | } 332 | if (scene.position == ScenePosition.EAST) { 333 | int totalHeight = height * (seatWidth + seatGap) - seatGap + offset; 334 | topX = totalHeight / 2 - height * 6; 335 | topY = offset / 2; 336 | bottomX = topX + scene.dimensionSecond; 337 | bottomY = topY + scene.dimension; 338 | } 339 | if (scene.position == ScenePosition.WEST) { 340 | int totalHeight = height * (seatWidth + seatGap) - seatGap + offset; 341 | topX = totalHeight / 2 - height * 6; 342 | topY = width * (seatWidth + seatGap) - seatGap + offset; 343 | bottomX = topX + scene.dimensionSecond; 344 | bottomY = topY + scene.dimension; 345 | } 346 | canvas.drawRect(topY, topX, bottomY, bottomX, backgroundPaint); 347 | canvas.save(); 348 | if (scene.position == ScenePosition.EAST) { 349 | canvas.rotate(270, (topY+bottomY)/2, (topX+bottomX)/2); 350 | } else if (scene.position == ScenePosition.WEST) { 351 | canvas.rotate(90, (topY+bottomY)/2, (topX+bottomX)/2); 352 | } 353 | drawTextCentred(canvas, scenePaint, sceneName, (topY+bottomY)/2, (topX+bottomX)/2); 354 | canvas.restore(); 355 | } 356 | 357 | private void drawTextCentred(Canvas canvas, Paint paint, String text, float cx, float cy){ 358 | paint.getTextBounds(text, 0, text.length(), textBounds); 359 | canvas.drawText(text, cx - textBounds.exactCenterX(), cy - textBounds.exactCenterY(), paint); 360 | } 361 | 362 | private void nullifyMap() { 363 | width = 0; 364 | height = 0; 365 | zones = new ArrayList<>(); 366 | image.setShouldOnMeasureBeCalled(true); 367 | } 368 | 369 | public void notifySeatListener(Seat s) { 370 | if (s.status() == SeatStatus.FREE) { 371 | if (listener != null) 372 | listener.selectSeat(s.id()); 373 | } else { 374 | if (listener != null) 375 | listener.unSelectSeat(s.id()); 376 | } 377 | } 378 | 379 | public static class Scene { 380 | 381 | private ScenePosition position; 382 | private int dimension; 383 | public int dimensionSecond; 384 | public int width, height, offset; 385 | 386 | public void setScenePosition(ScenePosition position, int offset) { 387 | this.position = position; 388 | this.offset = offset; 389 | dimension = 90; 390 | switch (position) { 391 | case NORTH: 392 | dimensionSecond = width * 12; 393 | break; 394 | case SOUTH: 395 | dimensionSecond = width * 12; 396 | break; 397 | case EAST: 398 | dimensionSecond = height * 12; 399 | break; 400 | case WEST: 401 | dimensionSecond = height * 12; 402 | break; 403 | case NONE: 404 | dimensionSecond = 0; 405 | dimension = 0; 406 | break; 407 | default: 408 | dimensionSecond = 0; 409 | dimension = 0; 410 | this.position = ScenePosition.NONE; 411 | break; 412 | } 413 | } 414 | 415 | public Scene(ScenePosition position, int width, int height, int offset) { 416 | this.width = width; 417 | this.height = height; 418 | setScenePosition(position, offset); 419 | } 420 | 421 | public int getTopXOffset() { 422 | if (position == ScenePosition.NORTH) { 423 | return dimension + offset; 424 | } 425 | return 0; 426 | } 427 | 428 | public int getLeftYOffset() { 429 | if (position == ScenePosition.EAST) { 430 | return dimension + offset; 431 | } 432 | return 0; 433 | } 434 | 435 | public int getBottomXOffset() { 436 | if (position == ScenePosition.SOUTH) { 437 | return dimension + offset; 438 | } 439 | return 0; 440 | } 441 | 442 | public int getRightYOffset() { 443 | if (position == ScenePosition.WEST) { 444 | return dimension + offset; 445 | } 446 | return 0; 447 | } 448 | 449 | @Override 450 | public String toString() { 451 | return String.format("Left - %d, Right- %d, Top - %d, Bottom - %d", getLeftYOffset(), getRightYOffset(), getTopXOffset(), getBottomXOffset()); 452 | } 453 | 454 | } 455 | 456 | public enum SeatStatus { 457 | FREE, BUSY, EMPTY, CHOSEN, INFO; 458 | 459 | public static boolean canSeatBePressed(SeatStatus status) { 460 | return (status == FREE || status == CHOSEN); 461 | } 462 | 463 | public SeatStatus pressSeat() { 464 | if (this == FREE) 465 | return CHOSEN; 466 | if (this == CHOSEN) 467 | return FREE; 468 | return this; 469 | } 470 | 471 | } 472 | 473 | @Override 474 | public String toString() { 475 | return String.format("height = %d; width = %d", height, width); 476 | } 477 | 478 | } -------------------------------------------------------------------------------- /library/src/main/java/by/anatoldeveloper/hallscheme/hall/ImageClickListener.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.hall; 2 | 3 | import android.graphics.Point; 4 | 5 | /** 6 | * Created by Nublo on 12.11.2015. 7 | * Copyright Nublo 8 | */ 9 | public interface ImageClickListener { 10 | 11 | void onClick(Point p); 12 | 13 | } -------------------------------------------------------------------------------- /library/src/main/java/by/anatoldeveloper/hallscheme/hall/MaxSeatsClickListener.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.hall; 2 | 3 | /** 4 | * Created by Nublo on 02.01.2016. 5 | * Copyright Nublo 6 | */ 7 | public interface MaxSeatsClickListener { 8 | 9 | void maxSeatsReached(int id); 10 | 11 | } -------------------------------------------------------------------------------- /library/src/main/java/by/anatoldeveloper/hallscheme/hall/ScenePosition.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.hall; 2 | 3 | /** 4 | * Created by Nublo on 05.12.2015. 5 | * Copyright Nublo 6 | */ 7 | public enum ScenePosition { 8 | NORTH, SOUTH, EAST, WEST, NONE 9 | } -------------------------------------------------------------------------------- /library/src/main/java/by/anatoldeveloper/hallscheme/hall/Seat.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.hall; 2 | 3 | /** 4 | * Created by Nublo on 28.10.2015. 5 | * Copyright Nublo 6 | */ 7 | public interface Seat { 8 | 9 | int id(); 10 | int color(); 11 | String marker(); 12 | String selectedSeat(); 13 | HallScheme.SeatStatus status(); 14 | void setStatus(HallScheme.SeatStatus status); 15 | 16 | } -------------------------------------------------------------------------------- /library/src/main/java/by/anatoldeveloper/hallscheme/hall/SeatListener.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.hall; 2 | 3 | /** 4 | * Created by Nublo on 12.11.2015. 5 | * Copyright Nublo 6 | */ 7 | public interface SeatListener { 8 | 9 | void selectSeat(int id); 10 | void unSelectSeat(int id); 11 | 12 | } -------------------------------------------------------------------------------- /library/src/main/java/by/anatoldeveloper/hallscheme/hall/Zone.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.hall; 2 | 3 | /** 4 | * Created by Nublo on 28.10.2015. 5 | * Copyright Nublo 6 | */ 7 | public interface Zone { 8 | 9 | int id(); 10 | int leftTopX(); 11 | int leftTopY(); 12 | int width(); 13 | int height(); 14 | int color(); 15 | String name(); 16 | 17 | } -------------------------------------------------------------------------------- /library/src/main/java/by/anatoldeveloper/hallscheme/hall/ZoneListener.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.hall; 2 | 3 | /** 4 | * Created by Moneyman.ru on 08.01.2016. 5 | * Copyright Moneyman.ru 6 | */ 7 | public interface ZoneListener { 8 | 9 | void zoneClick(int id); 10 | 11 | } -------------------------------------------------------------------------------- /library/src/main/java/by/anatoldeveloper/hallscheme/view/ZoomableImageView.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.view; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.graphics.Bitmap; 7 | import android.graphics.Matrix; 8 | import android.graphics.Point; 9 | import android.graphics.PointF; 10 | import android.util.AttributeSet; 11 | import android.view.GestureDetector; 12 | import android.view.MotionEvent; 13 | import android.view.ScaleGestureDetector; 14 | import android.view.View; 15 | import android.view.animation.DecelerateInterpolator; 16 | import android.widget.ImageView; 17 | 18 | import by.anatoldeveloper.hallscheme.R; 19 | import by.anatoldeveloper.hallscheme.hall.ImageClickListener; 20 | 21 | /** 22 | * Created by Nublo on 28.10.2015. 23 | * Copyright Nublo 24 | */ 25 | public class ZoomableImageView extends ImageView { 26 | 27 | private final static int ANIMATION_ZOOM_DURATION = 400; 28 | private final static float ANIMATION_ZOOM_PARAMETER = 1.3f; 29 | private static final int SWIPE_MIN_DISTANCE = 100; 30 | private static final int SWIPE_THRESHOLD_VELOCITY = 800; 31 | 32 | private Matrix matrix = new Matrix(); 33 | 34 | private static final int NONE = 0; 35 | private static final int DRAG = 1; 36 | private static final int ZOOM = 2; 37 | private static final int CLICK = 3; 38 | private int mode = NONE; 39 | 40 | private boolean isClick; 41 | 42 | private PointF last = new PointF(); 43 | private PointF start = new PointF(); 44 | private float minScale = 1f; 45 | private float maxScale = 3.0f; 46 | private float[] m; 47 | 48 | private float redundantXSpace, redundantYSpace; 49 | private float width, height; 50 | private float saveScale = 1f; 51 | private float right, bottom, origWidth, origHeight, bmWidth, bmHeight; 52 | 53 | private ScaleGestureDetector mScaleDetector; 54 | private GestureDetector mGestureDetector; 55 | private boolean shouldOnMeasureBeCalled = true; 56 | private int onMeasure = 0; 57 | 58 | private ImageClickListener listener; 59 | private boolean zoomByDoubleTap; 60 | 61 | public ZoomableImageView(Context context, AttributeSet attr) 62 | { 63 | super(context, attr); 64 | TypedArray a = context.getTheme().obtainStyledAttributes(attr, R.styleable.ZoomableImageView, 0, 0); 65 | try { 66 | zoomByDoubleTap = a.getBoolean(R.styleable.ZoomableImageView_doubleTap, true); 67 | } finally { 68 | a.recycle(); 69 | } 70 | super.setClickable(true); 71 | mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 72 | mGestureDetector = new GestureDetector(context, new GestureListener()); 73 | matrix.setTranslate(1f, 1f); 74 | m = new float[9]; 75 | setImageMatrix(matrix); 76 | setScaleType(ScaleType.MATRIX); 77 | 78 | setOnTouchListener(new OnTouchListener() 79 | { 80 | 81 | @Override 82 | public boolean onTouch(View v, MotionEvent event) 83 | { 84 | mScaleDetector.onTouchEvent(event); 85 | mGestureDetector.onTouchEvent(event); 86 | 87 | matrix.getValues(m); 88 | float x = m[Matrix.MTRANS_X]; 89 | float y = m[Matrix.MTRANS_Y]; 90 | PointF curr = new PointF(event.getX(), event.getY()); 91 | 92 | switch (event.getAction()) 93 | { 94 | case MotionEvent.ACTION_DOWN: 95 | last.set(event.getX(), event.getY()); 96 | start.set(last); 97 | mode = DRAG; 98 | isClick = true; 99 | break; 100 | case MotionEvent.ACTION_POINTER_DOWN: 101 | last.set(event.getX(), event.getY()); 102 | start.set(last); 103 | mode = ZOOM; 104 | break; 105 | case MotionEvent.ACTION_MOVE: 106 | if (isClick && (Math.abs(curr.x - last.x) > CLICK || Math.abs(curr.y-last.y) > CLICK)) { 107 | isClick = false; 108 | } 109 | if (mode == ZOOM || (mode == DRAG && saveScale > minScale)) 110 | { 111 | float deltaX = curr.x - last.x; 112 | float deltaY = curr.y - last.y; 113 | float scaleWidth = Math.round(origWidth * saveScale); 114 | float scaleHeight = Math.round(origHeight * saveScale); 115 | if (scaleWidth < width) 116 | { 117 | deltaX = 0; 118 | if (y + deltaY > 0) 119 | deltaY = -y; 120 | else if (y + deltaY < -bottom) 121 | deltaY = -(y + bottom); 122 | } 123 | else if (scaleHeight < height) 124 | { 125 | deltaY = 0; 126 | if (x + deltaX > 0) 127 | deltaX = -x; 128 | else if (x + deltaX < -right) 129 | deltaX = -(x + right); 130 | } 131 | else 132 | { 133 | if (x + deltaX > 0) 134 | deltaX = -x; 135 | else if (x + deltaX < -right) 136 | deltaX = -(x + right); 137 | 138 | if (y + deltaY > 0) 139 | deltaY = -y; 140 | else if (y + deltaY < -bottom) 141 | deltaY = -(y + bottom); 142 | } 143 | matrix.postTranslate(deltaX, deltaY); 144 | last.set(curr.x, curr.y); 145 | } 146 | break; 147 | 148 | case MotionEvent.ACTION_UP: 149 | mode = NONE; 150 | int xDiff = (int) Math.abs(curr.x - start.x); 151 | int yDiff = (int) Math.abs(curr.y - start.y); 152 | if (xDiff < CLICK && yDiff < CLICK) 153 | performClick(); 154 | if (isClick) { 155 | v.performClick(); 156 | if (listener != null) { 157 | listener.onClick(new Point((int)((event.getX()-x)/m[0]), (int)((event.getY()-y)/m[0]))); 158 | } 159 | } 160 | break; 161 | 162 | case MotionEvent.ACTION_POINTER_UP: 163 | mode = NONE; 164 | break; 165 | } 166 | setImageMatrix(matrix); 167 | invalidate(); 168 | return true; 169 | } 170 | 171 | }); 172 | } 173 | 174 | public void setClickListener(ImageClickListener listener) { 175 | this.listener = listener; 176 | } 177 | 178 | public void setZoomByDoubleTap(boolean zoomByDoubleTap) { 179 | this.zoomByDoubleTap = zoomByDoubleTap; 180 | } 181 | 182 | @Override 183 | public boolean performClick() { 184 | return super.performClick(); 185 | } 186 | 187 | @Override 188 | public void setImageBitmap(Bitmap bm) 189 | { 190 | super.setImageBitmap(bm); 191 | bmWidth = bm.getWidth(); 192 | bmHeight = bm.getHeight(); 193 | } 194 | 195 | public void setShouldOnMeasureBeCalled(boolean b) { 196 | if (b) { 197 | onMeasure = 0; 198 | } 199 | this.shouldOnMeasureBeCalled = b; 200 | } 201 | 202 | public void zoom(boolean zoomIn) { 203 | float endScale; 204 | if (zoomIn) endScale = saveScale * ANIMATION_ZOOM_PARAMETER; 205 | else endScale = saveScale / ANIMATION_ZOOM_PARAMETER; 206 | if (endScale > maxScale) endScale = maxScale; 207 | if (endScale < minScale) endScale = minScale; 208 | ValueAnimator zoomAnimation = ValueAnimator.ofFloat(saveScale, endScale); 209 | zoomAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 210 | @Override 211 | public void onAnimationUpdate(ValueAnimator valueAnimator) { 212 | float value = (Float) valueAnimator.getAnimatedValue(); 213 | zoomScale(value); 214 | } 215 | }); 216 | zoomAnimation.setDuration(ANIMATION_ZOOM_DURATION); 217 | zoomAnimation.start(); 218 | } 219 | 220 | public void zoomScale(float endScale) { 221 | scale(endScale/saveScale, width/2, height/2); 222 | setImageMatrix(matrix); 223 | invalidate(); 224 | } 225 | 226 | private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener 227 | { 228 | 229 | @Override 230 | public boolean onScaleBegin(ScaleGestureDetector detector) { 231 | mode = ZOOM; 232 | return true; 233 | } 234 | 235 | @Override 236 | public boolean onScale(ScaleGestureDetector detector) { 237 | scale(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY()); 238 | return true; 239 | } 240 | } 241 | 242 | private void scale(float scaleFactor, float xCenter, float yCenter) { 243 | float origScale = saveScale; 244 | saveScale *= scaleFactor; 245 | if (saveScale > maxScale) { 246 | saveScale = maxScale; 247 | scaleFactor = maxScale / origScale; 248 | } 249 | else if (saveScale < minScale) { 250 | saveScale = minScale; 251 | scaleFactor = minScale / origScale; 252 | } 253 | right = width * saveScale - width - (2 * redundantXSpace * saveScale); 254 | bottom = height * saveScale - height - (2 * redundantYSpace * saveScale); 255 | if (origWidth * saveScale <= width || origHeight * saveScale <= height) 256 | { 257 | matrix.postScale(scaleFactor, scaleFactor, width / 2, height / 2); 258 | if (scaleFactor < 1) 259 | { 260 | matrix.getValues(m); 261 | float x = m[Matrix.MTRANS_X]; 262 | float y = m[Matrix.MTRANS_Y]; 263 | if (scaleFactor < 1) 264 | { 265 | if (Math.round(origWidth * saveScale) < width) 266 | { 267 | if (y < -bottom) 268 | matrix.postTranslate(0, -(y + bottom)); 269 | else if (y > 0) 270 | matrix.postTranslate(0, -y); 271 | } 272 | else 273 | { 274 | if (x < -right) 275 | matrix.postTranslate(-(x + right), 0); 276 | else if (x > 0) 277 | matrix.postTranslate(-x, 0); 278 | } 279 | } 280 | } 281 | } 282 | else 283 | { 284 | matrix.postScale(scaleFactor, scaleFactor, xCenter, yCenter); 285 | matrix.getValues(m); 286 | float x = m[Matrix.MTRANS_X]; 287 | float y = m[Matrix.MTRANS_Y]; 288 | if (scaleFactor < 1) { 289 | if (x < -right) 290 | matrix.postTranslate(-(x + right), 0); 291 | else if (x > 0) 292 | matrix.postTranslate(-x, 0); 293 | if (y < -bottom) 294 | matrix.postTranslate(0, -(y + bottom)); 295 | else if (y > 0) 296 | matrix.postTranslate(0, -y); 297 | } 298 | } 299 | } 300 | 301 | private class GestureListener extends GestureDetector.SimpleOnGestureListener { 302 | 303 | @Override 304 | public boolean onDoubleTap( MotionEvent e ) { 305 | if (zoomByDoubleTap) 306 | zoom(true); 307 | return false; 308 | } 309 | 310 | @Override 311 | public void onLongPress( MotionEvent e ) {} 312 | 313 | @Override 314 | public boolean onScroll( MotionEvent e1, MotionEvent e2, float distanceX, float distanceY ) { return false;} 315 | 316 | @Override 317 | public boolean onFling( MotionEvent e1, MotionEvent e2, float velocityX, float velocityY ) { 318 | if (e1 == null || e2 == null) return false; 319 | if ( e1.getPointerCount() > 1 || e2.getPointerCount() > 1 ) return false; 320 | if ( mScaleDetector.isInProgress() || mode == ZOOM) return false; 321 | if ( (Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY || Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) && 322 | (Math.abs(e2.getX() - e1.getX()) > SWIPE_MIN_DISTANCE || Math.abs(e2.getY() - e1.getY()) > SWIPE_MIN_DISTANCE)) { 323 | float diffX = e2.getX() - e1.getX(); 324 | float diffY = e2.getY() - e1.getY(); 325 | //animateFling(velocityX/20, velocityY/20); 326 | animateFling(diffX, diffY); 327 | return true; 328 | } 329 | return false; 330 | } 331 | } 332 | 333 | private void animateFling(final float diffX, final float diffY) { 334 | ValueAnimator flingAnimation = ValueAnimator.ofFloat(diffX/5, 0); 335 | flingAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 336 | @Override 337 | public void onAnimationUpdate(ValueAnimator valueAnimator) { 338 | float newDiffX = (float) valueAnimator.getAnimatedValue(); 339 | float newDiffY = (newDiffX * diffY)/diffX; 340 | flingMatrix(newDiffX, newDiffY); 341 | } 342 | }); 343 | flingAnimation.setDuration(300); 344 | flingAnimation.setInterpolator(new DecelerateInterpolator()); 345 | flingAnimation.start(); 346 | } 347 | 348 | private void flingMatrix(float xValue, float yValue) { 349 | right = width * saveScale - width - (2 * redundantXSpace * saveScale); 350 | bottom = height * saveScale - height - (2 * redundantYSpace * saveScale); 351 | matrix.getValues(m); 352 | float x = m[Matrix.MTRANS_X]; 353 | float y = m[Matrix.MTRANS_Y]; 354 | float xFreeSpace = width - (origWidth * saveScale); 355 | xFreeSpace = (xFreeSpace < 0) ? 0.0f : xFreeSpace / 2; 356 | if ((x + xValue - xFreeSpace) <= -right) { 357 | xValue = -(x + right + xFreeSpace); 358 | } 359 | else if ((x + xValue - xFreeSpace) >= 0) { 360 | xValue = -x; 361 | } 362 | float yFreeSpace = height - (origHeight * saveScale); 363 | yFreeSpace = (yFreeSpace < 0) ? 0.0f : yFreeSpace / 2; 364 | if ((y + yValue - yFreeSpace) <= -bottom) { 365 | yValue = -(y + bottom + yFreeSpace); 366 | } else if ((y + yValue - yFreeSpace) >= 0) { 367 | yValue = -y; 368 | } 369 | matrix.postTranslate(xValue, yValue); 370 | setImageMatrix(matrix); 371 | invalidate(); 372 | } 373 | 374 | @Override 375 | protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) 376 | { 377 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 378 | if (!shouldOnMeasureBeCalled && onMeasure > 2) { 379 | return; 380 | } else if (!shouldOnMeasureBeCalled) { 381 | onMeasure++; 382 | } 383 | width = MeasureSpec.getSize(widthMeasureSpec); 384 | height = MeasureSpec.getSize(heightMeasureSpec); 385 | //Fit to screen. 386 | float scale = Math.min(width / bmWidth, height / bmHeight); 387 | matrix.setScale(scale, scale); 388 | setImageMatrix(matrix); 389 | saveScale = 1f; 390 | 391 | // Center the image 392 | redundantYSpace = height - (scale * bmHeight); 393 | redundantXSpace = width - (scale * bmWidth); 394 | redundantYSpace /= 2; 395 | redundantXSpace /= 2; 396 | 397 | matrix.postTranslate(redundantXSpace, redundantYSpace); 398 | 399 | origWidth = width - 2 * redundantXSpace; 400 | origHeight = height - 2 * redundantYSpace; 401 | right = width * saveScale - width - (2 * redundantXSpace * saveScale); 402 | bottom = height * saveScale - height - (2 * redundantYSpace * saveScale); 403 | setImageMatrix(matrix); 404 | } 405 | 406 | } -------------------------------------------------------------------------------- /library/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /library/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #A8B4BA 4 | #282828 5 | #FF6600 6 | #FFFFFF 7 | #FFD8E2E6 8 | #FF424242 9 | #FFF7F7F7 10 | #FF4F7514 11 | #FF661141 12 | 13 | -------------------------------------------------------------------------------- /library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | HallScheme 3 | Scene 4 | 5 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.1" 6 | 7 | defaultConfig { 8 | applicationId "by.anatoldeveloper.hallscheme.example" 9 | minSdkVersion 14 10 | targetSdkVersion 25 11 | versionCode 2 12 | versionName "1.1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile 'com.android.support:appcompat-v7:25.0.1' 24 | compile project(':library') 25 | } 26 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /sample/src/main/assets/fonts/DroidSansMono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nublo/HallScheme/7ac4bf085dae23c14d0b40c70e61d2f0e43a1bbb/sample/src/main/assets/fonts/DroidSansMono.ttf -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.LayoutInflater; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.AdapterView; 14 | import android.widget.ArrayAdapter; 15 | import android.widget.ListView; 16 | 17 | import by.anatoldeveloper.hallscheme.example.schemes.SchemeBasic; 18 | import by.anatoldeveloper.hallscheme.example.schemes.SchemeCustomTypeface; 19 | import by.anatoldeveloper.hallscheme.example.schemes.SchemeDarkTheme; 20 | import by.anatoldeveloper.hallscheme.example.schemes.SchemeMaxSelectedSeats; 21 | import by.anatoldeveloper.hallscheme.example.schemes.SchemeWithMarkers; 22 | import by.anatoldeveloper.hallscheme.example.schemes.SchemeWithScene; 23 | import by.anatoldeveloper.hallscheme.example.schemes.SchemeWithZones; 24 | 25 | /** 26 | * Created by Nublo on 06.12.2015. 27 | * Copyright Nublo 28 | */ 29 | 30 | public class MainActivity extends AppCompatActivity { 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_main); 36 | getSupportFragmentManager().beginTransaction().replace(R.id.main_fragment, new ListFragment()).commit(); 37 | } 38 | 39 | @Override 40 | public boolean onCreateOptionsMenu(Menu menu) { 41 | getMenuInflater().inflate(R.menu.main_menu, menu); 42 | return true; 43 | } 44 | 45 | @Override 46 | public boolean onOptionsItemSelected(MenuItem item) { 47 | switch (item.getItemId()) { 48 | case R.id.open_on_github: 49 | openOnGithub(); 50 | return true; 51 | default: 52 | return super.onOptionsItemSelected(item); 53 | } 54 | } 55 | 56 | private void openOnGithub() { 57 | Intent openBrowser = new Intent(Intent.ACTION_VIEW); 58 | openBrowser.setData(Uri.parse("https://github.com/Nublo/HallScheme")); 59 | startActivity(openBrowser); 60 | } 61 | 62 | public static class ListFragment extends Fragment { 63 | 64 | private static final String[] halls = {"Basic hall scheme", "Scheme with scene", "Scheme with markers", 65 | "Custom colors scheme", "Custom typeface", "Maximum selected seats", "Scheme with zones"}; 66 | 67 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 68 | View rootView = inflater.inflate(R.layout.halls_fragment, container, false); 69 | ListView hallListView = (ListView) rootView.findViewById(R.id.hall_examples); 70 | ArrayAdapter listAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, halls); 71 | hallListView.setAdapter(listAdapter); 72 | 73 | hallListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 74 | @Override 75 | public void onItemClick(AdapterView parent, View view, int position, long id) { 76 | switch (position) { 77 | case 0 : 78 | replaceFragmentAndAddToBackStack(new SchemeBasic()); 79 | break; 80 | case 1 : 81 | replaceFragmentAndAddToBackStack(new SchemeWithScene()); 82 | break; 83 | case 2 : 84 | replaceFragmentAndAddToBackStack(new SchemeWithMarkers()); 85 | break; 86 | case 3 : 87 | replaceFragmentAndAddToBackStack(new SchemeDarkTheme()); 88 | break; 89 | case 4 : 90 | replaceFragmentAndAddToBackStack(new SchemeCustomTypeface()); 91 | break; 92 | case 5 : 93 | replaceFragmentAndAddToBackStack(new SchemeMaxSelectedSeats()); 94 | break; 95 | case 6 : 96 | replaceFragmentAndAddToBackStack(new SchemeWithZones()); 97 | break; 98 | } 99 | } 100 | }); 101 | return rootView; 102 | } 103 | 104 | public void replaceFragmentAndAddToBackStack(Fragment fragment) { 105 | getActivity().getSupportFragmentManager() 106 | .beginTransaction() 107 | .replace(R.id.main_fragment, fragment) 108 | .addToBackStack(null) 109 | .commit(); 110 | } 111 | 112 | } 113 | 114 | } -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/SeatExample.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example; 2 | 3 | import android.graphics.Color; 4 | 5 | import by.anatoldeveloper.hallscheme.hall.HallScheme; 6 | import by.anatoldeveloper.hallscheme.hall.Seat; 7 | 8 | /** 9 | * Created by Nublo on 05.12.2015. 10 | * Copyright Nublo 11 | */ 12 | public class SeatExample implements Seat { 13 | 14 | public int id; 15 | public int color = Color.RED; 16 | public String marker; 17 | public String selectedSeatMarker; 18 | public HallScheme.SeatStatus status; 19 | 20 | @Override 21 | public int id() { 22 | return id; 23 | } 24 | 25 | @Override 26 | public int color() { 27 | return color; 28 | } 29 | 30 | @Override 31 | public String marker() { 32 | return marker; 33 | } 34 | 35 | @Override 36 | public String selectedSeat() { 37 | return selectedSeatMarker; 38 | } 39 | 40 | @Override 41 | public HallScheme.SeatStatus status() { 42 | return status; 43 | } 44 | 45 | @Override 46 | public void setStatus(HallScheme.SeatStatus status) { 47 | this.status = status; 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/ZoneExample.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example; 2 | 3 | import by.anatoldeveloper.hallscheme.hall.Zone; 4 | 5 | /** 6 | * Created by Nublo on 08.01.2016. 7 | * Copyright Nublo 8 | */ 9 | public class ZoneExample implements Zone { 10 | 11 | public int id; 12 | public int leftTopX; 13 | public int leftTopY; 14 | public int width; 15 | public int height; 16 | public int color; 17 | public String name; 18 | 19 | public ZoneExample() { 20 | 21 | } 22 | 23 | public ZoneExample(int id, int leftTopX, int leftTopY, int width, int height, int color, String name) { 24 | this.id = id; 25 | this.leftTopX = leftTopX; 26 | this.leftTopY = leftTopY; 27 | this.width = width; 28 | this.height = height; 29 | this.color = color; 30 | this.name = name; 31 | } 32 | 33 | @Override 34 | public int id() { 35 | return id; 36 | } 37 | 38 | @Override 39 | public int leftTopX() { 40 | return leftTopX; 41 | } 42 | 43 | @Override 44 | public int leftTopY() { 45 | return leftTopY; 46 | } 47 | 48 | @Override 49 | public int width() { 50 | return width; 51 | } 52 | 53 | @Override 54 | public int height() { 55 | return height; 56 | } 57 | 58 | @Override 59 | public int color() { 60 | return color; 61 | } 62 | 63 | @Override 64 | public String name() { 65 | return name; 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/schemes/SchemeBasic.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example.schemes; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.Toast; 10 | 11 | import by.anatoldeveloper.hallscheme.example.R; 12 | import by.anatoldeveloper.hallscheme.example.SeatExample; 13 | import by.anatoldeveloper.hallscheme.hall.HallScheme; 14 | import by.anatoldeveloper.hallscheme.hall.Seat; 15 | import by.anatoldeveloper.hallscheme.hall.SeatListener; 16 | import by.anatoldeveloper.hallscheme.view.ZoomableImageView; 17 | 18 | /** 19 | * Created by Nublo on 05.12.2015. 20 | * Copyright Nublo 21 | */ 22 | public class SchemeBasic extends Fragment { 23 | 24 | @Nullable 25 | @Override 26 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 27 | View rootView = inflater.inflate(R.layout.basic_scheme_fragment, container, false); 28 | ZoomableImageView imageView = (ZoomableImageView) rootView.findViewById(R.id.zoomable_image); 29 | HallScheme scheme = new HallScheme(imageView, basicScheme(), getActivity()); 30 | scheme.setSeatListener(new SeatListener() { 31 | 32 | @Override 33 | public void selectSeat(int id) { 34 | Toast.makeText(getActivity(), "select seat " + id, Toast.LENGTH_SHORT).show(); 35 | } 36 | 37 | @Override 38 | public void unSelectSeat(int id) { 39 | Toast.makeText(getActivity(), "unSelect seat " + id, Toast.LENGTH_SHORT).show(); 40 | } 41 | 42 | }); 43 | return rootView; 44 | } 45 | 46 | public Seat[][] basicScheme() { 47 | Seat seats[][] = new Seat[10][10]; 48 | for (int i = 0; i < 10; i++) 49 | for(int j = 0; j < 10; j++) { 50 | SeatExample seat = new SeatExample(); 51 | seat.id = i * 10 + (j+1); 52 | seat.selectedSeatMarker = String.valueOf(j+1); 53 | seat.status = HallScheme.SeatStatus.FREE; 54 | seats[i][j] = seat; 55 | } 56 | return seats; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/schemes/SchemeCustomTypeface.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example.schemes; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.Typeface; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.Fragment; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.Button; 12 | import android.widget.Toast; 13 | 14 | import by.anatoldeveloper.hallscheme.example.R; 15 | import by.anatoldeveloper.hallscheme.example.SeatExample; 16 | import by.anatoldeveloper.hallscheme.hall.HallScheme; 17 | import by.anatoldeveloper.hallscheme.hall.ScenePosition; 18 | import by.anatoldeveloper.hallscheme.hall.Seat; 19 | import by.anatoldeveloper.hallscheme.hall.SeatListener; 20 | import by.anatoldeveloper.hallscheme.view.ZoomableImageView; 21 | 22 | /** 23 | * Created by Nublo on 03.01.2016. 24 | * Copyright Nublo 25 | */ 26 | public class SchemeCustomTypeface extends Fragment { 27 | 28 | boolean doubleTap = false; 29 | 30 | @Nullable 31 | @Override 32 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 33 | View rootView = inflater.inflate(R.layout.scheme_with_button, container, false); 34 | final ZoomableImageView imageView = (ZoomableImageView) rootView.findViewById(R.id.zoomable_image); 35 | final Button zoomButton = (Button) rootView.findViewById(R.id.scheme_button); 36 | zoomButton.setOnClickListener(new View.OnClickListener() { 37 | @Override 38 | public void onClick(View v) { 39 | doubleTap = !doubleTap; 40 | imageView.setZoomByDoubleTap(doubleTap); 41 | if (doubleTap) { 42 | zoomButton.setText(getString(R.string.double_tap_enabled)); 43 | } else { 44 | zoomButton.setText(getString(R.string.double_tap_disabled)); 45 | } 46 | } 47 | }); 48 | HallScheme scheme = new HallScheme(imageView, basicScheme(), getActivity()); 49 | scheme.setScenePosition(ScenePosition.NORTH); 50 | scheme.setSeatListener(new SeatListener() { 51 | 52 | @Override 53 | public void selectSeat(int id) { 54 | Toast.makeText(getActivity(), "select seat " + id, Toast.LENGTH_SHORT).show(); 55 | } 56 | 57 | @Override 58 | public void unSelectSeat(int id) { 59 | Toast.makeText(getActivity(), "unSelect seat " + id, Toast.LENGTH_SHORT).show(); 60 | } 61 | 62 | }); 63 | scheme.setTypeface(Typeface.createFromAsset(getActivity().getAssets(), "fonts/DroidSansMono.ttf")); 64 | return rootView; 65 | } 66 | 67 | public Seat[][] basicScheme() { 68 | Seat seats[][] = new Seat[7][14]; 69 | int k = 0; 70 | for (int i = 0; i < 7; i++) 71 | for(int j = 0; j < 14; j++) { 72 | SeatExample seat = new SeatExample(); 73 | seat.id = ++k; 74 | seat.selectedSeatMarker = String.valueOf(j+1); 75 | seat.status = HallScheme.SeatStatus.BUSY; 76 | if (j == 0 || j == 13) { 77 | seat.marker = String.valueOf(i+1); 78 | seat.status = HallScheme.SeatStatus.INFO; 79 | } 80 | if (j > 5 && j < 8) { 81 | seat.status = HallScheme.SeatStatus.EMPTY; 82 | } 83 | if (((j > 0 && j < 6) || (j > 7 && j < 13)) && i < 2) { 84 | seat.status = HallScheme.SeatStatus.FREE; 85 | seat.color = Color.RED; 86 | } 87 | if (((j > 0 && j < 6) || (j > 7 && j < 13)) && i > 4) { 88 | seat.status = HallScheme.SeatStatus.FREE; 89 | seat.color = Color.GREEN; 90 | } 91 | seats[i][j] = seat; 92 | } 93 | return seats; 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/schemes/SchemeDarkTheme.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example.schemes; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.Toast; 10 | 11 | import by.anatoldeveloper.hallscheme.example.R; 12 | import by.anatoldeveloper.hallscheme.example.SeatExample; 13 | import by.anatoldeveloper.hallscheme.hall.HallScheme; 14 | import by.anatoldeveloper.hallscheme.hall.ScenePosition; 15 | import by.anatoldeveloper.hallscheme.hall.Seat; 16 | import by.anatoldeveloper.hallscheme.hall.SeatListener; 17 | import by.anatoldeveloper.hallscheme.view.ZoomableImageView; 18 | 19 | /** 20 | * Created by Nublo on 06.12.2015. 21 | * Copyright Nublo 22 | */ 23 | public class SchemeDarkTheme extends Fragment { 24 | 25 | @Nullable 26 | @Override 27 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 28 | View rootView = inflater.inflate(R.layout.basic_scheme_fragment, container, false); 29 | rootView.setBackgroundColor(getActivity().getResources().getColor(R.color.dark_grey)); 30 | ZoomableImageView imageView = (ZoomableImageView) rootView.findViewById(R.id.zoomable_image); 31 | HallScheme scheme = new HallScheme(imageView, schemeWithDifferentColors(), getActivity()); 32 | scheme.setBackgroundColor(getActivity().getResources().getColor(R.color.dark_grey)); 33 | scheme.setScenePosition(ScenePosition.EAST); 34 | scheme.setSceneTextColor(getActivity().getResources().getColor(R.color.dark_grey)); 35 | scheme.setChosenSeatTextColor(getActivity().getResources().getColor(R.color.dark_grey)); 36 | scheme.setSceneBackgroundColor(getActivity().getResources().getColor(R.color.white)); 37 | scheme.setMarkerColor(getActivity().getResources().getColor(R.color.white)); 38 | scheme.setChosenSeatBackgroundColor(getActivity().getResources().getColor(R.color.white)); 39 | scheme.setSeatListener(new SeatListener() { 40 | 41 | @Override 42 | public void selectSeat(int id) { 43 | Toast.makeText(getActivity(), "select seat " + id, Toast.LENGTH_SHORT).show(); 44 | } 45 | 46 | @Override 47 | public void unSelectSeat(int id) { 48 | Toast.makeText(getActivity(), "unSelect seat " + id, Toast.LENGTH_SHORT).show(); 49 | } 50 | 51 | }); 52 | return rootView; 53 | } 54 | 55 | public Seat[][] schemeWithDifferentColors() { 56 | Seat seats[][] = new Seat[14][12]; 57 | for (int i = 0; i < 14; i++) 58 | for(int j = 0; j < 12; j++) { 59 | SeatExample seat = new SeatExample(); 60 | seat.id = i * 10 + (j+1); 61 | seat.selectedSeatMarker = String.valueOf(i+1); 62 | seat.status = HallScheme.SeatStatus.BUSY; 63 | if (j < 2) { 64 | seat.status = HallScheme.SeatStatus.FREE; 65 | seat.color = getActivity().getResources().getColor(R.color.dark_green); 66 | } 67 | if (j == 11) { 68 | seat.status = HallScheme.SeatStatus.FREE; 69 | seat.color = getActivity().getResources().getColor(R.color.dark_purple); 70 | } 71 | if (i == 0 || i == 13) { 72 | seat.status = HallScheme.SeatStatus.EMPTY; 73 | } 74 | if ((i == 1 || i == 12) && j != 11) { 75 | seat.status = HallScheme.SeatStatus.EMPTY; 76 | } 77 | if ((i == 2 || i == 11) && (j < 2 || j == 7)) { 78 | seat.status = HallScheme.SeatStatus.EMPTY; 79 | } 80 | if ((i == 3 || i == 10) && (j < 1 || j == 7)) { 81 | seat.status = HallScheme.SeatStatus.EMPTY; 82 | } 83 | if ((i == 4 || i == 9) && (j > 7)) { 84 | seat.status = HallScheme.SeatStatus.EMPTY; 85 | } 86 | if (j == 7) { 87 | seat.status = HallScheme.SeatStatus.EMPTY; 88 | } 89 | if (i == 0 && j == 11) { 90 | seat.status = HallScheme.SeatStatus.INFO; 91 | seat.marker = String.valueOf(11); 92 | } 93 | if (i == 1 && (j > 7 && j < 11)) { 94 | seat.status = HallScheme.SeatStatus.INFO; 95 | seat.marker = String.valueOf(j); 96 | } 97 | if (i == 1 && (j > 1 && j < 7)) { 98 | seat.status = HallScheme.SeatStatus.INFO; 99 | seat.marker = String.valueOf(j+1); 100 | } 101 | if (i == 2 && j == 1) { 102 | seat.status = HallScheme.SeatStatus.INFO; 103 | seat.marker = String.valueOf(j+1); 104 | } 105 | if (i == 3 && j == 0) { 106 | seat.status = HallScheme.SeatStatus.INFO; 107 | seat.marker = String.valueOf(j+1); 108 | } 109 | seats[i][j] = seat; 110 | } 111 | return seats; 112 | } 113 | 114 | } -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/schemes/SchemeMaxSelectedSeats.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example.schemes; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Button; 11 | import android.widget.Toast; 12 | 13 | import by.anatoldeveloper.hallscheme.example.R; 14 | import by.anatoldeveloper.hallscheme.example.SeatExample; 15 | import by.anatoldeveloper.hallscheme.hall.HallScheme; 16 | import by.anatoldeveloper.hallscheme.hall.MaxSeatsClickListener; 17 | import by.anatoldeveloper.hallscheme.hall.ScenePosition; 18 | import by.anatoldeveloper.hallscheme.hall.Seat; 19 | import by.anatoldeveloper.hallscheme.hall.SeatListener; 20 | import by.anatoldeveloper.hallscheme.view.ZoomableImageView; 21 | 22 | /** 23 | * Created by Nublo on 30.01.2016. 24 | * Copyright Nublo 25 | */ 26 | public class SchemeMaxSelectedSeats extends Fragment { 27 | 28 | @Nullable 29 | @Override 30 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 31 | View rootView = inflater.inflate(R.layout.scheme_with_button, container, false); 32 | ZoomableImageView imageView = (ZoomableImageView) rootView.findViewById(R.id.zoomable_image); 33 | final HallScheme scheme = new HallScheme(imageView, basicScheme(), getActivity()); 34 | scheme.setScenePosition(ScenePosition.NORTH); 35 | scheme.setSeatListener(new SeatListener() { 36 | 37 | @Override 38 | public void selectSeat(int id) { 39 | Toast.makeText(getActivity(), "select seat " + id, Toast.LENGTH_SHORT).show(); 40 | } 41 | 42 | @Override 43 | public void unSelectSeat(int id) { 44 | Toast.makeText(getActivity(), "unSelect seat " + id, Toast.LENGTH_SHORT).show(); 45 | } 46 | 47 | }); 48 | scheme.setMaxSelectedSeats(5); 49 | scheme.setMaxSeatsClickListener(new MaxSeatsClickListener() { 50 | @Override 51 | public void maxSeatsReached(int id) { 52 | Toast.makeText(getActivity(), "Maximum selected seat limit reached", Toast.LENGTH_SHORT).show(); 53 | } 54 | }); 55 | Button clickButton = (Button) rootView.findViewById(R.id.scheme_button); 56 | clickButton.setText(getString(R.string.programmatically_click)); 57 | clickButton.setOnClickListener(new View.OnClickListener() { 58 | @Override 59 | public void onClick(View v) { 60 | scheme.clickSchemeProgrammatically(1, 1); 61 | } 62 | }); 63 | return rootView; 64 | } 65 | 66 | public Seat[][] basicScheme() { 67 | Seat seats[][] = new Seat[7][14]; 68 | int k = 0; 69 | for (int i = 0; i < 7; i++) 70 | for(int j = 0; j < 14; j++) { 71 | SeatExample seat = new SeatExample(); 72 | seat.id = ++k; 73 | seat.selectedSeatMarker = String.valueOf(j+1); 74 | seat.status = HallScheme.SeatStatus.BUSY; 75 | if (j == 0 || j == 13) { 76 | seat.marker = String.valueOf(i+1); 77 | seat.status = HallScheme.SeatStatus.INFO; 78 | } 79 | if (j > 5 && j < 8) { 80 | seat.status = HallScheme.SeatStatus.EMPTY; 81 | } 82 | if (((j > 0 && j < 6) || (j > 7 && j < 13)) && i < 2) { 83 | seat.status = HallScheme.SeatStatus.FREE; 84 | seat.color = Color.RED; 85 | } 86 | if (((j > 0 && j < 6) || (j > 7 && j < 13)) && i > 4) { 87 | seat.status = HallScheme.SeatStatus.FREE; 88 | seat.color = Color.GREEN; 89 | } 90 | seats[i][j] = seat; 91 | } 92 | return seats; 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/schemes/SchemeWithMarkers.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example.schemes; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.Toast; 10 | 11 | import by.anatoldeveloper.hallscheme.example.R; 12 | import by.anatoldeveloper.hallscheme.example.SeatExample; 13 | import by.anatoldeveloper.hallscheme.hall.HallScheme; 14 | import by.anatoldeveloper.hallscheme.hall.ScenePosition; 15 | import by.anatoldeveloper.hallscheme.hall.Seat; 16 | import by.anatoldeveloper.hallscheme.hall.SeatListener; 17 | import by.anatoldeveloper.hallscheme.view.ZoomableImageView; 18 | 19 | /** 20 | * Created by Nublo on 06.12.2015. 21 | * Copyright Nublo 22 | */ 23 | public class SchemeWithMarkers extends Fragment { 24 | 25 | @Nullable 26 | @Override 27 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 28 | View rootView = inflater.inflate(R.layout.basic_scheme_fragment, container, false); 29 | ZoomableImageView imageView = (ZoomableImageView) rootView.findViewById(R.id.zoomable_image); 30 | HallScheme scheme = new HallScheme(imageView, basicScheme(), getActivity()); 31 | scheme.setSceneName(getString(R.string.custom_name)); 32 | scheme.setScenePosition(ScenePosition.NORTH); 33 | scheme.setSeatListener(new SeatListener() { 34 | 35 | @Override 36 | public void selectSeat(int id) { 37 | Toast.makeText(getActivity(), "select seat " + id, Toast.LENGTH_SHORT).show(); 38 | } 39 | 40 | @Override 41 | public void unSelectSeat(int id) { 42 | Toast.makeText(getActivity(), "unSelect seat " + id, Toast.LENGTH_SHORT).show(); 43 | } 44 | 45 | }); 46 | return rootView; 47 | } 48 | 49 | public Seat[][] basicScheme() { 50 | Seat seats[][] = new Seat[12][18]; 51 | int k = 0; 52 | for (int i = 0; i < 12; i++) 53 | for(int j = 0; j < 18; j++) { 54 | SeatExample seat = new SeatExample(); 55 | seat.id = ++k; 56 | seat.selectedSeatMarker = String.valueOf(i+1); 57 | seat.status = HallScheme.SeatStatus.BUSY; 58 | if (j == 0 || j == 17) { 59 | seat.status = HallScheme.SeatStatus.EMPTY; 60 | if (i > 2 && i < 10) { 61 | seat.marker = String.valueOf(i); 62 | seat.status = HallScheme.SeatStatus.INFO; 63 | } 64 | } 65 | if (((j > 0 && j < 3) || (j > 14 && j < 17)) && i == 0) { 66 | seat.status = HallScheme.SeatStatus.EMPTY; 67 | if (j == 2 || j == 15) { 68 | seat.marker = String.valueOf(i+1); 69 | seat.status = HallScheme.SeatStatus.INFO; 70 | } 71 | } 72 | if (((j > 0 && j < 2) || (j > 15 && j < 17)) && i == 1) { 73 | seat.status = HallScheme.SeatStatus.EMPTY; 74 | if (j == 1 || j == 16) { 75 | seat.marker = String.valueOf(i+1); 76 | seat.status = HallScheme.SeatStatus.INFO; 77 | } 78 | } 79 | if (i == 2) 80 | seat.status = HallScheme.SeatStatus.EMPTY; 81 | if (i > 9 && (j == 1 || j == 16)) { 82 | seat.status = HallScheme.SeatStatus.INFO; 83 | seat.marker = String.valueOf(i); 84 | } 85 | seats[i][j] = seat; 86 | } 87 | return seats; 88 | } 89 | 90 | } -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/schemes/SchemeWithScene.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example.schemes; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Toast; 11 | 12 | import by.anatoldeveloper.hallscheme.example.R; 13 | import by.anatoldeveloper.hallscheme.example.SeatExample; 14 | import by.anatoldeveloper.hallscheme.hall.HallScheme; 15 | import by.anatoldeveloper.hallscheme.hall.ScenePosition; 16 | import by.anatoldeveloper.hallscheme.hall.Seat; 17 | import by.anatoldeveloper.hallscheme.hall.SeatListener; 18 | import by.anatoldeveloper.hallscheme.view.ZoomableImageView; 19 | 20 | /** 21 | * Created by Nublo on 05.12.2015. 22 | * Copyright Nublo 23 | */ 24 | public class SchemeWithScene extends Fragment { 25 | 26 | @Nullable 27 | @Override 28 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 29 | View rootView = inflater.inflate(R.layout.basic_scheme_fragment, container, false); 30 | ZoomableImageView imageView = (ZoomableImageView) rootView.findViewById(R.id.zoomable_image); 31 | HallScheme scheme = new HallScheme(imageView, schemeWithScene(), getActivity()); 32 | scheme.setScenePosition(ScenePosition.SOUTH); 33 | scheme.setSeatListener(new SeatListener() { 34 | 35 | @Override 36 | public void selectSeat(int id) { 37 | Toast.makeText(getActivity(), "select seat " + id, Toast.LENGTH_SHORT).show(); 38 | } 39 | 40 | @Override 41 | public void unSelectSeat(int id) { 42 | Toast.makeText(getActivity(), "unSelect seat " + id, Toast.LENGTH_SHORT).show(); 43 | } 44 | 45 | }); 46 | return rootView; 47 | } 48 | 49 | public Seat[][] schemeWithScene() { 50 | Seat seats[][] = new Seat[16][29]; 51 | int k = 0; 52 | for (int i = 0; i < 16; i++) 53 | for(int j = 0; j < 29; j++) { 54 | SeatExample seat = new SeatExample(); 55 | seat.id = ++k; 56 | seat.selectedSeatMarker = String.valueOf(j+1); 57 | seat.status = HallScheme.SeatStatus.EMPTY; 58 | seats[i][j] = seat; 59 | if (i < 5 && j < 4) { 60 | seat.status = HallScheme.SeatStatus.BUSY; 61 | if (i < 4) { 62 | seat.status = HallScheme.SeatStatus.FREE; 63 | seat.color = Color.argb(255, 60, 179, 113); 64 | } 65 | } 66 | if (j > 1 && j < 5 && i > 4) { 67 | seat.status = HallScheme.SeatStatus.BUSY; 68 | if (i > 13) { 69 | seat.status = HallScheme.SeatStatus.FREE; 70 | seat.color = Color.argb(255, 148, 51, 145); 71 | } 72 | } 73 | if (j == 4 && i > 1 && i < 5) 74 | seat.status = HallScheme.SeatStatus.BUSY; 75 | if (i < 5 && j > 24) { 76 | seat.status = HallScheme.SeatStatus.BUSY; 77 | if (i < 4) { 78 | seat.status = HallScheme.SeatStatus.FREE; 79 | seat.color = Color.argb(255, 60, 179, 113); 80 | } 81 | } 82 | if (j > 23 && j < 27 && i > 4) { 83 | seat.status = HallScheme.SeatStatus.BUSY; 84 | if (i > 13) { 85 | seat.status = HallScheme.SeatStatus.FREE; 86 | seat.color = Color.argb(255, 148, 51, 145); 87 | } 88 | } 89 | if (j == 24 && i > 1 && i < 5) 90 | seat.status = HallScheme.SeatStatus.BUSY; 91 | if (i > 3 && j > 6 && j < 22) { 92 | seat.status = HallScheme.SeatStatus.BUSY; 93 | if (i > 13) { 94 | seat.status = HallScheme.SeatStatus.FREE; 95 | seat.color = Color.argb(255, 43, 108, 196); 96 | } 97 | } 98 | 99 | } 100 | return seats; 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /sample/src/main/java/by/anatoldeveloper/hallscheme/example/schemes/SchemeWithZones.java: -------------------------------------------------------------------------------- 1 | package by.anatoldeveloper.hallscheme.example.schemes; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Toast; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | import by.anatoldeveloper.hallscheme.example.R; 16 | import by.anatoldeveloper.hallscheme.example.SeatExample; 17 | import by.anatoldeveloper.hallscheme.example.ZoneExample; 18 | import by.anatoldeveloper.hallscheme.hall.HallScheme; 19 | import by.anatoldeveloper.hallscheme.hall.ScenePosition; 20 | import by.anatoldeveloper.hallscheme.hall.Seat; 21 | import by.anatoldeveloper.hallscheme.hall.SeatListener; 22 | import by.anatoldeveloper.hallscheme.hall.Zone; 23 | import by.anatoldeveloper.hallscheme.hall.ZoneListener; 24 | import by.anatoldeveloper.hallscheme.view.ZoomableImageView; 25 | 26 | /** 27 | * Created by Nublo on 31.01.2016. 28 | * Copyright Nublo 29 | */ 30 | public class SchemeWithZones extends Fragment { 31 | 32 | @Nullable 33 | @Override 34 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 35 | View rootView = inflater.inflate(R.layout.basic_scheme_fragment, container, false); 36 | ZoomableImageView imageView = (ZoomableImageView) rootView.findViewById(R.id.zoomable_image); 37 | HallScheme scheme = new HallScheme(imageView, schemeWithScene(), getActivity()); 38 | scheme.setScenePosition(ScenePosition.SOUTH); 39 | scheme.setSeatListener(new SeatListener() { 40 | 41 | @Override 42 | public void selectSeat(int id) { 43 | Toast.makeText(getActivity(), "select seat " + id, Toast.LENGTH_SHORT).show(); 44 | } 45 | 46 | @Override 47 | public void unSelectSeat(int id) { 48 | Toast.makeText(getActivity(), "unSelect seat " + id, Toast.LENGTH_SHORT).show(); 49 | } 50 | 51 | }); 52 | scheme.setZones(zones()); 53 | scheme.setZoneListener(new ZoneListener() { 54 | @Override 55 | public void zoneClick(int id) { 56 | Toast.makeText(getActivity(), "Zone click " + id, Toast.LENGTH_SHORT).show(); 57 | } 58 | }); 59 | return rootView; 60 | } 61 | 62 | public Seat[][] schemeWithScene() { 63 | Seat seats[][] = new Seat[23][26]; 64 | int k = 0; 65 | for (int i = 0; i < 23; i++) 66 | for(int j = 0; j < 26; j++) { 67 | SeatExample seat = new SeatExample(); 68 | seat.id = ++k; 69 | seat.selectedSeatMarker = String.valueOf(j+1); 70 | seat.status = HallScheme.SeatStatus.EMPTY; 71 | seats[i][j] = seat; 72 | if (i == 22 && (j < 5 || j > 20)) { 73 | seat.status = HallScheme.SeatStatus.BUSY; 74 | } 75 | if (i == 21 && (j < 6 || j > 19)) { 76 | seat.status = HallScheme.SeatStatus.BUSY; 77 | } 78 | if (i == 20 && (j < 7 || j > 18)) { 79 | seat.status = HallScheme.SeatStatus.BUSY; 80 | } 81 | if (i > 16 && i < 21 && (j < 7 || j > 18)) { 82 | seat.status = HallScheme.SeatStatus.BUSY; 83 | } 84 | if (i > 7 && i < 16 && (j < 6 || j > 19)) { 85 | seat.status = HallScheme.SeatStatus.BUSY; 86 | } 87 | if (i == 4 && (j < 5 || j > 20)) { 88 | seat.status = HallScheme.SeatStatus.BUSY; 89 | } 90 | if (i > 4 && i < 8 && (j < 3 || j > 22)) { 91 | seat.status = HallScheme.SeatStatus.FREE; 92 | seat.color = Color.GREEN; 93 | } 94 | 95 | } 96 | return seats; 97 | } 98 | 99 | public List zones() { 100 | List zones = new ArrayList<>(); 101 | ZoneExample zone1 = new ZoneExample(1, 8, 17, 10, 6, getActivity().getResources().getColor(R.color.dark_green), "Not used in current version"); 102 | ZoneExample zone2 = new ZoneExample(2, 8, 4, 10, 12, Color.DKGRAY, "Not used in current version"); 103 | ZoneExample zone3 = new ZoneExample(3, 0, 0, 26, 2, getActivity().getResources().getColor(R.color.dark_purple), "Not used in current version"); 104 | zones.add(zone1); 105 | zones.add(zone2); 106 | zones.add(zone3); 107 | return zones; 108 | } 109 | 110 | } -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/basic_scheme_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/halls_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/scheme_with_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 |