diff --git a/.gitignore b/.gitignore index d350491b9a97d635edcda4e5763da18ac1c89efc..f1533f403607bb6f8f89275248a68f1a7acbd7b2 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ android/gen/ *.iml out/ com_crashlytics_export_strings.xml +captures ## Eclipse .classpath diff --git a/android/assets/keystore/tablexiaTrustKeystore b/android/assets/keystore/tablexiaTrustKeystore index d644ca6543ae7c7342c4c342d9becf120c251213..44a14512de3dd5d7cb50de0ec5ddd0c22d417046 100644 Binary files a/android/assets/keystore/tablexiaTrustKeystore and b/android/assets/keystore/tablexiaTrustKeystore differ diff --git a/android/assets/text/application/application_de.properties b/android/assets/text/application/application_de.properties index c2302488dc878a3278dcc393d914d49bea133171..cab9f70fd374231aafaa06566e74ab99deeaac18 100644 --- a/android/assets/text/application/application_de.properties +++ b/android/assets/text/application/application_de.properties @@ -60,8 +60,8 @@ game_averagescore_error=Durchschnittliche Fehlerzahl: game_averagescore_duration=Durchschnittliche Spieldauer: game_quit_question=Möchtest du wirklich das Spiel beenden? -sound_muted_question=[DE]Pro pokraÄŤovánĂ je zapotĹ™ebĂ mĂt zapnutĂ˝ zvuk. PĹ™eješ si nynĂ zvuk zapnout a pokraÄŤovat?[DE] -sound_muted_game_question=[DE]Pro pokraÄŤovánĂ ve hĹ™e je zapotĹ™ebĂ mĂt zapnutĂ˝ zvuk. PĹ™eješ si nynĂ zvuk zapnout a pokraÄŤovat?[DE] +sound_muted_question=Um fortzufahren ist es notwendig, dass der Ton eingeschalten ist. Möchtest du jetzt den Ton einschalten und fortfahren? +sound_muted_game_question=Um das Spiel fortzusetzen ist es notwendig, dass der Ton eingeschalten ist. Möchtest du jetzt den Ton einschalten und fortsetzen? game_robbery_title=Einbrecher game_robbery_description=Training des Arbeitsgedächtnisses @@ -185,5 +185,5 @@ user_rank_9=Kleiner Kommissar user_rank_10=Besserwisser user_rank_11=Oberrat -sync_request_dialog_text=Trage deine Ausweisnummer ein: +sync_request_dialog_text=Trage deine Ausweisnummer ein\: sync_request_button=Account synchronisieren diff --git a/android/assets/text/screen/halloffame/halloffame_cs.properties b/android/assets/text/screen/halloffame/halloffame_cs.properties index c5aecf885633571baed7fc0bc29e89f183180d88..920a5745051d356e2eb915a1010ae85d44694e40 100644 --- a/android/assets/text/screen/halloffame/halloffame_cs.properties +++ b/android/assets/text/screen/halloffame/halloffame_cs.properties @@ -6,24 +6,24 @@ mouse_0_1=Kde nic, tu nic. Medaile, ani salám.\r\nRadši mazej do práce, chyta mouse_0_2=Tak co tu ještÄ› okounĂš? mouse_0_3=TobÄ› pĹ™ijde divnĂ˝, Ĺľe myš mluvĂ? mouse_0_4=To budou asi pĹ™eludy z toho prázdna tady. -mouse_4_1=ŽádnĂ˝ bohatstvĂ tu ještÄ› nemáš, ale aspoĹ nÄ›co. -mouse_5_1=ProstÄ› pár trofejĂ... Ăşdivem z toho teda nepadám. -mouse_6_1=Bejt tebou, jdu lovit dalšĂ, aĹĄ se máš ÄŤĂm chlubit. +mouse_4_1=ŽádnĂ˝ bohatstvĂ tu ještÄ› nemáš,\r\nale aspoĹ nÄ›co. +mouse_5_1=ProstÄ› pár trofejĂ...\r\nĂşdivem z toho teda nepadám. +mouse_6_1=Bejt tebou, jdu lovit dalšĂ,\r\naĹĄ se máš ÄŤĂm chlubit. mouse_9_1=Je vidÄ›t, Ĺľe jsi na sobÄ› pracoval, ale dobĹ™Ă\r\ndetektivovĂ© majĂ trofejĂ ještÄ› vĂc. mouse_13_1=Tak se pokochej a zase do práce. mouse_14_1=Tak ještÄ› chvili pokoukat, pohladit,\r\npĹ™eleštit, ale neusĂnej na vavĹ™Ănech. mouse_16_1=MoĹľná, Ĺľe to dotáhneš daleko. -mouse_17_1=Ty mÄ› pĹ™ekvapuješ! Vypadá to, Ĺľe to myslĂš vážnÄ›. -mouse_19_1=Je vidÄ›t, Ĺľe jsi na svou sbĂrku trofejĂ pyšnĂ˝. Taky uĹľ máš na co. +mouse_17_1=Ty mÄ› pĹ™ekvapuješ! Vypadá to,\r\nĹľe to myslĂš vážnÄ›. +mouse_19_1=Je vidÄ›t, Ĺľe jsi na svou sbĂrku trofejĂ pyšnĂ˝.\r\nTaky uĹľ máš na co. mouse_21_1=MoĹľná, Ĺľe o tobÄ› ještÄ› uslyšĂme. mouse_21_2=MoĹľná taky ne, to záležà na tom,\r\njak na sobÄ› ještÄ› zapracuješ. mouse_21_3=KdyĹľ tu budeš ještÄ› okounÄ›t, tak o tobÄ›\r\nspĂš uĹľ neuslyšĂme. -mouse_25_1=Zas tolik se nenaparuj, ještÄ› ti jich pár chybĂ. -mouse_28_1=Ĺ˝e zbylĂ© trofeje za chvĂli posbĂráš? To Ĺ™Ăkal kaĹľdĂ˝ detektiv. -mouse_29_1=Pro mÄ› za mÄ›, klidnÄ› si je prohlĂĹľej, ale ty zbylĂ© trofeje se samy neposbĂrajĂ. +mouse_25_1=Zas tolik se nenaparuj,\r\nještÄ› ti jich pár chybĂ. +mouse_28_1=Ĺ˝e zbylĂ© trofeje za chvĂli posbĂráš?\r\nTo Ĺ™Ăkal kaĹľdĂ˝ detektiv. +mouse_29_1=Pro mÄ› za mÄ›, klidnÄ› si je prohlĂĹľej,\r\nale ty zbylĂ© trofeje se samy neposbĂrajĂ. mouse_30_1=Ă“ jistÄ›, detektiv tvĂ©ho formátu má na všechno dost ÄŤasu. -mouse_31_1=To vypadá, Ĺľe je tu\r\nnÄ›kdo hodnÄ› ambiciĂłznĂ. -mouse_32_1=To nenĂ samo sebou sesbĂrat skoro všechny trofeje. +mouse_31_1=To vypadá, Ĺľe je tu nÄ›kdo hodnÄ› ambiciĂłznĂ. +mouse_32_1=To nenĂ samo sebou sesbĂrat skoro\r\nvšechny trofeje. mouse_33_1=VsadĂm svĹŻj ocas, Ĺľe ty zbylĂ© uĹľ neposbĂráš. mouse_34_1=Tolik trofejĂ. ĂšctyhodnĂ˝ vĂ˝kon. mouse_36_1=Tak to tu ještÄ› nebylo! diff --git a/android/assets/text/screen/halloffame/halloffame_de.properties b/android/assets/text/screen/halloffame/halloffame_de.properties index 803e8c1a62be2f965c974c004ff56b95b5d9e74a..ba74ff48eefc65cb3ad5deb7325f4adb9348623f 100644 --- a/android/assets/text/screen/halloffame/halloffame_de.properties +++ b/android/assets/text/screen/halloffame/halloffame_de.properties @@ -6,31 +6,31 @@ mouse_0_1=Von nichts kommt nichts. Hier ist noch keine Medaille.\r\nMach dich li mouse_0_2=Na was stehst du hier noch rum? mouse_0_3=Du wunderst dich, dass eine Maus sprechen kann? mouse_0_4=Das ist wohl eine Fata Morgana von der Leere hier. -mouse_4_1=Du hast hier noch keinen Reichtum, aber wenigstens etwas. -mouse_5_1=Nur ein paar Trophäen ... also vor Staunen fall ich noch nicht um. -mouse_6_1=An deiner Stelle wĂĽrde ich noch weitere ergattern, dann kannst du damit prahlen. -mouse_9_1=Man sieht, dass du an dir gearbeitet hast, aber gute\r\nDetektive haben noch mehr Trophäen. +mouse_4_1=Du hast hier noch keinen Reichtum,\r\naber wenigstens etwas. +mouse_5_1=Nur ein paar Trophäen...\r\nalso vor Staunen fall ich noch nicht um. +mouse_6_1=An deiner Stelle wĂĽrde ich noch weitere ergattern,\r\ndann kannst du damit prahlen. +mouse_9_1=Man sieht, dass du an dir gearbeitet hast,\r\naber gute Detektive haben noch mehr Trophäen. mouse_13_1=Dann schau dich kurz um und wieder an die Arbeit. -mouse_14_1=Noch ein wenig schauen, streicheln,\r\npolieren, aber ruh dich nicht auf deinen Lorbeeren aus. +mouse_14_1=Noch ein wenig schauen, streicheln, polieren,\r\naber ruh dich nicht auf deinen Lorbeeren aus. mouse_16_1=Vielleicht bringst du es weit. -mouse_17_1=Du ĂĽberraschst mich! Es sieht aus, als wĂĽrdest du es ernst meinen. -mouse_19_1=Man sieht, dass du auf deine Trophäensammlung stolz bist. Du hast auch allen Grund. +mouse_17_1=Du ĂĽberraschst mich! Es sieht aus,\r\nals wĂĽrdest du es ernst meinen. +mouse_19_1=Man sieht, dass du auf deine Trophäensammlung\r\nstolz bist. Du hast auch allen Grund. mouse_21_1=Vielleicht hören wir noch etwas von dir. mouse_21_2=Vielleicht auch nicht, das hängt davon ab,\r\nwie sehr du noch an dir arbeitest. -mouse_21_3=Wenn du dir hier nur die Trophäen anschaust, dann wird man von dir\r\neher nichts mehr hören. -mouse_25_1=Gib aber nicht so viel damit an, dir fehlen noch ein paar Trophäen. -mouse_28_1=Die fehlenden Trophäen sammelst du\r\nsicher in einer Weile, richtig? Das hat jeder Detektiv/jede Detektivin gesagt. +mouse_21_3=Wenn du dir hier nur die Trophäen anschaust,\r\ndann wird man von dir\r\neher nichts mehr hören. +mouse_25_1=Gib aber nicht so viel damit an,\r\ndir fehlen noch ein paar Trophäen. +mouse_28_1=Die fehlenden Trophäen sammelst\r\ndu sicher in einer Weile, richtig?\r\nDas hat jeder Detektiv/jede Detektivin gesagt. mouse_29_1=Meinetwegen, schau sie dir ruhig\r\nan, aber die fehlenden\r\nTrophäen sammeln sich nicht von allein. -mouse_30_1=Na sicher, ein Detektiv/eine Detektivin von deinem Format hat fĂĽr alles genĂĽgend Zeit. +mouse_30_1=Na sicher, ein Detektiv/eine Detektivin\r\nvon deinem Format hat fĂĽr alles genĂĽgend Zeit. mouse_31_1=Es sieht so aus, dass hier\r\njemand groĂźe Ambitionen hat. -mouse_32_1=Das geht nicht von allein, fast alle Trophäen zu sammeln. -mouse_33_1=Ich verwette meine Schneidezähne, dass du die ĂĽbrigen nicht mehr einsammelst. +mouse_32_1=Das geht nicht von allein,\r\nfast alle Trophäen zu sammeln. +mouse_33_1=Ich verwette meine Schneidezähne,\r\ndass du die ĂĽbrigen nicht mehr einsammelst. mouse_34_1=So viele Trophäen. Respektable Leistung. mouse_36_1=Na das hat es hier noch nicht gegeben! mouse_36_2=Alle Ehre, das habe ich noch nicht gesehen.\r\nUnd ich wohne hier schon ganz schön lange. mouse_36_3=Davon werden sich noch meine Enkel erzählen. -mouse_rankup=Herzlichen GlĂĽckwunsch zur Beförderung! Mach weiter so! +mouse_rankup=Herzlichen GlĂĽckwunsch zur Beförderung!\r\nMach weiter so! # <!-- Skrin s hodnostmi --> badge_cabinet_list=Dienstgradliste diff --git a/android/assets/text/screen/halloffame/halloffame_sk.properties b/android/assets/text/screen/halloffame/halloffame_sk.properties index 7cb86879f4b305ef08d2362869cc7d5937fc05c9..0db53a7810854b2284d47f09aa3c0a8c58944ddb 100644 --- a/android/assets/text/screen/halloffame/halloffame_sk.properties +++ b/android/assets/text/screen/halloffame/halloffame_sk.properties @@ -2,32 +2,32 @@ count_sum=Celkom mouse_bubble=ÄŚoĹľe to myška povedala? # <!-- Myška --> -mouse_0_1=Kde niÄŤ, tu niÄŤ. Ani medaile, ani saláma. Radšej utekaj do práce chytaĹĄ lupiÄŤov. +mouse_0_1=Kde niÄŤ, tu niÄŤ. Ani medaile, ani saláma.\r\nRadšej utekaj do práce chytaĹĄ lupiÄŤov. mouse_0_2=Tak ÄŤo tu ešte okĂşĹaš? mouse_0_3=Tebe prĂde divnĂ©, Ĺľe myš hovorĂ? mouse_0_4=To budĂş asi preÄľudy z tohto prázdna. -mouse_4_1=Ĺ˝iadne bohatstvo tu ešte nemáš, ale aspoĹ nieÄŤo. -mouse_5_1=Proste pár trofejĂ...Ăşdivom z toho teda nepadám. -mouse_6_1=Na tvojom mieste idem loviĹĄ ÄŹalšie, nech sa máš ÄŤĂm pochváliĹĄ. -mouse_9_1=Je vidieĹĄ, Ĺľe si na sebe pracoval, ale dobrĂ detektĂvovia majĂş trofejĂ ešte viac. +mouse_4_1=Ĺ˝iadne bohatstvo tu ešte nemáš,\r\nale aspoĹ nieÄŤo. +mouse_5_1=Proste pár trofejĂ...\r\nĂşdivom z toho teda nepadám. +mouse_6_1=Na tvojom mieste idem loviĹĄ ÄŹalšie,\r\nnech sa máš ÄŤĂm pochváliĹĄ. +mouse_9_1=Je vidieĹĄ, Ĺľe si na sebe pracoval,\r\nale dobrĂ detektĂvovia majĂş trofejĂ ešte viac. mouse_13_1=Tak sa pokochaj a zase do práce. -mouse_14_1=Tak ešte chvĂÄľu popozeraĹĄ, pohladiĹĄ, preleštiĹĄ, ale nespĂ na vavrĂnoch. +mouse_14_1=Tak ešte chvĂÄľu popozeraĹĄ, pohladiĹĄ,\r\npreleštiĹĄ, ale nespĂ na vavrĂnoch. mouse_16_1=MoĹľno to ešte dotiahneš ÄŹaleko. -mouse_17_1=Ty ma prekvapuješ! Vyzerá to tak, Ĺľe to myslĂš vážne. -mouse_19_1=Je vidieĹĄ, Ĺľe si na svoju zbierku trofejĂ pyšnĂ˝. TieĹľ uĹľ máš na ÄŤo. +mouse_17_1=Ty ma prekvapuješ!\r\nVyzerá to tak, Ĺľe to myslĂš vážne. +mouse_19_1=Je vidieĹĄ, Ĺľe si na svoju zbierku trofejĂ pyšnĂ˝.\r\nTieĹľ uĹľ máš na ÄŤo. mouse_21_1=MoĹľno o tebe budeme ešte poÄŤuĹĄ. -mouse_21_2=MoĹľno tieĹľ nie, to záležà na tom, ako na sebe ešte zapracuješ. -mouse_21_3=KeÄŹ tu budeš ešte okĂşĹaĹĄ, tak o tebe skĂ´r uĹľ nebudeme poÄŤuĹĄ. -mouse_25_1=Zas toÄľko sa nenaparuj, ešte ti pár TrofejĂ chĂ˝ba. -mouse_28_1=Ĺ˝e zvyšnĂ© trofeje za chvĂÄľu pozbieraš? To hovoril kaĹľdĂ˝ detektĂv. -mouse_29_1=Pre mĹa za mĹa, kÄľudne si ich prezeraj, ale tie zvyšnĂ© trofeje sa samĂ© nepozbierajĂş. -mouse_30_1=Ă“ urÄŤite, detektĂv tvojho formátu má na všetko dosĹĄ ÄŤasu. -mouse_31_1=Vyzerá to tak, Ĺľe je tu niekto veÄľmi ambiciĂłzny. -mouse_32_1=To nieje len tak, vyzbieraĹĄ skoro všetky trofeje. +mouse_21_2=MoĹľno tieĹľ nie, to záležà na tom,\r\nako na sebe ešte zapracuješ. +mouse_21_3=KeÄŹ tu budeš ešte okĂşĹaĹĄ,\r\ntak o tebe skĂ´r uĹľ nebudeme poÄŤuĹĄ. +mouse_25_1=Zas toÄľko sa nenaparuj,\r\nešte ti pár TrofejĂ chĂ˝ba. +mouse_28_1=Ĺ˝e zvyšnĂ© trofeje za chvĂÄľu pozbieraš?\r\nTo hovoril kaĹľdĂ˝ detektĂv. +mouse_29_1=Pre mĹa za mĹa, kÄľudne si ich prezeraj,\r\nale tie zvyšnĂ© trofeje sa samĂ© nepozbierajĂş. +mouse_30_1=Ă“ urÄŤite, detektĂv tvojho formátu\r\nmá na všetko dosĹĄ ÄŤasu. +mouse_31_1=Vyzerá to tak, Ĺľe je tu niekto\r\nveÄľmi ambiciĂłzny. +mouse_32_1=To nieje len tak, vyzbieraĹĄ skoro\r\nvšetky trofeje. mouse_33_1=VsadĂm sa, Ĺľe tie ostatnĂ© uĹľ nepozbieraš. mouse_34_1=ToÄľko trofejĂ. ĂšctyhodnĂ˝ vĂ˝kon. mouse_36_1=Tak to tu ešte nebolo! -mouse_36_2=Všetká ÄŤesĹĄ, toto som ešte nevidela. A to tu bĂ˝vam uĹľ celkom dlho. +mouse_36_2=Všetká ÄŤesĹĄ, toto som ešte nevidela.\r\nA to tu bĂ˝vam uĹľ celkom dlho. mouse_36_3=O tom si budĂş rozprávaĹĄ ešte moje vnúčatá. mouse_rankup=Gratulujem k povýšenie. Len tak ÄŹalej! diff --git a/android/build.gradle b/android/build.gradle index 3ace2e011e69128dda6e973572ceb8d8933fc8a0..65eeb3794b1b1cbf13091604d05b0bada4079b1e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -29,18 +29,21 @@ android { applicationIdSuffix rootProject.applicationIdBranch + rootProject.applicationIdDebugSuffix buildConfigField ASSETS_CHECKSUM_FIELD_TYPE, ASSETS_CHECKSUM_FIELD_NAME, rootProject.ext.assetsChecksumPattern resValue "string", "app_name", "${tablexiaAppName}" + resValue "string", "sentry_dsn", project.hasProperty('TABLEXIA_SENTRY_DSN_DEBUG') ? "$TABLEXIA_SENTRY_DSN_DEBUG" : "$project.sentryDSNFallbackValue"; } release { debuggable false applicationIdSuffix rootProject.applicationIdBranch buildConfigField ASSETS_CHECKSUM_FIELD_TYPE, ASSETS_CHECKSUM_FIELD_NAME, rootProject.ext.assetsChecksumPattern resValue "string", "app_name", "${tablexiaAppName}" + resValue "string", "sentry_dsn", project.hasProperty('TABLEXIA_SENTRY_DSN_RELEASE') ? "$TABLEXIA_SENTRY_DSN_RELEASE" : "$project.sentryDSNFallbackValue"; } devel.initWith(buildTypes.debug) devel { applicationIdSuffix rootProject.applicationIdDevelSuffix buildConfigField ASSETS_CHECKSUM_FIELD_TYPE, ASSETS_CHECKSUM_FIELD_NAME, rootProject.ext.assetsChecksumPattern resValue "string", "app_name", "${tablexiaAppName}" + resValue "string", "sentry_dsn", "$project.sentryDSNFallbackValue"; } } diff --git a/android/src/main/java/cz/nic/tablexia/android/AndroidLauncher.java b/android/src/main/java/cz/nic/tablexia/android/AndroidLauncher.java index db84cebc95ec5f11c52b2d5eb44069aa58b1c20e..8a09145f2a36ea66a14f0800573dfaa6e2f7d9a0 100644 --- a/android/src/main/java/cz/nic/tablexia/android/AndroidLauncher.java +++ b/android/src/main/java/cz/nic/tablexia/android/AndroidLauncher.java @@ -4,6 +4,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Matrix; import android.net.ConnectivityManager; +import android.os.Build; import android.os.Bundle; import com.badlogic.gdx.Gdx; @@ -18,6 +19,7 @@ import cz.nic.tablexia.Tablexia; import cz.nic.tablexia.TablexiaBuildConfig; import cz.nic.tablexia.TablexiaSettings; import cz.nic.tablexia.debug.BuildConfig; +import cz.nic.tablexia.debug.R; import cz.nic.tablexia.screen.loader.IConnectionManager; import cz.nic.tablexia.util.Log; @@ -41,8 +43,10 @@ public class AndroidLauncher extends AndroidApplication { getResources().getConfiguration().locale, SQL_CONNECTION_TYPE, new AndroidConnectionManager(getContext()), + getResources().getString(R.string.sentry_dsn), HAS_SOFT_BACK_BUTTON, - savedInstanceState == null), config); + savedInstanceState == null, + Build.SERIAL), config); if (TablexiaSettings.getInstance().getBuildType().isBugReport() && TablexiaBuildConfig.FLURRY_KEY != null) { FlurryAgent.setLogEnabled(false); @@ -95,23 +99,34 @@ public class AndroidLauncher extends AndroidApplication { @Override public boolean isUsingMobileData() { + return getConnectionType() == ConnectionType.Mobile; + } + + @Override + public ConnectionType getConnectionType() { ConnectivityManager conMan = (ConnectivityManager) androidContext.getSystemService(Context.CONNECTIVITY_SERVICE); - //We are not connected to the internet at all... + //We are not connected to the internet at all... if(conMan == null || conMan.getActiveNetworkInfo() == null) - return false; + return ConnectionType.Unknown; - //Is user using any of mobile internet types ? Hope I didn't miss any... + //Is user using any of mobile internet types ? Hope I didn't miss any... switch (conMan.getActiveNetworkInfo().getType()) { case ConnectivityManager.TYPE_MOBILE: case ConnectivityManager.TYPE_MOBILE_DUN: case ConnectivityManager.TYPE_MOBILE_HIPRI: case ConnectivityManager.TYPE_MOBILE_MMS: case ConnectivityManager.TYPE_MOBILE_SUPL: - return true; + return ConnectionType.Mobile; + + case ConnectivityManager.TYPE_ETHERNET: + return ConnectionType.Ethernet; + + case ConnectivityManager.TYPE_WIFI: + return ConnectionType.Wifi; default: - return false; + return ConnectionType.Unknown; } } } diff --git a/build.gradle b/build.gradle index e7ed8bb50e3fcef2a735687bca0345f07c313b15..1424a411d018a38906e5b6c427ffda1431f2a6a0 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,9 @@ import com.badlogic.gdx.tools.texturepacker.TexturePacker buildscript { repositories { -// mavenCentral() - maven { url 'https://jitpack.io' } - jcenter{ url "http://jcenter.bintray.com/" } + maven { url "http://repo1.maven.org/maven2" } + maven { url "https://jitpack.io" } + jcenter { url "http://jcenter.bintray.com/" } } dependencies { classpath 'com.android.tools.build:gradle:2.0.0' @@ -13,7 +13,7 @@ buildscript { classpath 'de.felixschulze.gradle:gradle-spoon-plugin:2.1' classpath 'com.github.JakeWharton:sdk-manager-plugin:220bf7a88a7072df3ed16dc8466fb144f2817070' classpath 'com.novoda:gradle-android-command-plugin:1.3.0' - classpath "com.badlogicgames.gdx:gdx-tools:1.6.1" + classpath 'com.badlogicgames.gdx:gdx-tools:1.6.1' } } @@ -26,6 +26,9 @@ final assetsGameGlobalDirectory = "_global" final assetsGameCommonDifficultyDirectory = "common" final assetsGameExcludedDirectory = "excluded" +final String TABLEXIA_GIT_PATH = './' +final String MODEL_GIT_PATH = 'core/external/' + System.setProperty("javax.net.ssl.trustStore", new File("${project(":android").projectDir.absolutePath}/assets/keystore/tablexiaTrustKeystore").getAbsolutePath()); System.setProperty("javax.net.ssl.trustStorePassword", "tablexia"); @@ -45,8 +48,10 @@ allprojects { masterBranch = 'master' applicationBaseId = 'cz.nic.tablexia' tablexiaAppName = getTablexiaAppName() - tablexiaVersionName = getVersionNameFromGit() - tablexiaVersionCode = getVersionCodeFromGit() + tablexiaVersionName = getVersionNameFromGit(TABLEXIA_GIT_PATH) + tablexiaVersionCode = getVersionCodeFromGit(TABLEXIA_GIT_PATH) + tablexiaModelVersionName = getVersionNameFromGit(MODEL_GIT_PATH) + tablexiaModelVersionCode = getVersionCodeFromGit(MODEL_GIT_PATH) applicationIdBranch = getTablexiaAppId() applicationIdRelease = applicationBaseId + applicationIdBranch applicationIdDebugSuffix = '.debug' @@ -54,6 +59,9 @@ allprojects { applicationIdDevelSuffix = '.devel' applicationIdDevel = applicationBaseId + applicationIdDevelSuffix + //Fallback value if sentry DSN is not defined (gradle parameter SENTRY_DSN_DEBUG or SENTRY_DSN_RELEASE) + sentryDSNFallbackValue = "None" + gdxVersion = '1.9.2' gdxUtilsVersion = '0.13.2' mbassadorVersion = '1.2.0' @@ -64,17 +72,18 @@ allprojects { roboPodsVersion = '1.13.0' androidSupportV4Version = '22.0.0' googlePlayServicesVersion = '8.3.+' + + servletApiVersion = '5.5.23' + ravenVersion = '7.5.0' } - version = getVersionNameFromGit() + version = getVersionNameFromGit(TABLEXIA_GIT_PATH) repositories { - mavenCentral() - jcenter { - url "http://jcenter.bintray.com/" - } - maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } - maven { url "https://oss.sonatype.org/content/repositories/releases/" } + maven { url "http://repo1.maven.org/maven2" } + jcenter { url "http://jcenter.bintray.com/" } + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } + maven { url "https://oss.sonatype.org/content/repositories/releases/" } } } @@ -266,12 +275,13 @@ def getTablexiaAppId() { } } -def getVersionNameFromGit() { +def getVersionNameFromGit(String relativePath) { def stdout = new ByteArrayOutputStream() String branchName = getBranchNameFromGit() // get last tag in current branch exec { + workingDir relativePath commandLine 'git', 'describe', '--abbrev=0', '--tags' standardOutput = stdout } @@ -281,6 +291,7 @@ def getVersionNameFromGit() { if (!project.masterBranch.equals(branchName)) { stdout = new ByteArrayOutputStream() exec { + workingDir relativePath commandLine 'git', 'rev-list', "${result}..HEAD", '--count' standardOutput = stdout } @@ -294,9 +305,10 @@ def getVersionNameFromGit() { return result } -def getVersionCodeFromGit() { +def getVersionCodeFromGit(String relativePath) { def stdout = new ByteArrayOutputStream() exec { + workingDir relativePath commandLine 'git', 'log', '-1', '--format=%at' standardOutput = stdout } @@ -400,6 +412,8 @@ project(":core") { compile "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" compile "com.google.guava:guava:$guavaVersion" + compile "tomcat:servlet-api:$servletApiVersion" + compile "com.getsentry.raven:raven:$ravenVersion" testCompile "junit:junit:4.11" testCompile "com.badlogicgames.gdx:gdx-backend-headless:$gdxVersion" diff --git a/core/assets/common/_global/application/mainmenu/button_sound_pressed.png b/core/assets/common/_global/application/mainmenu/button_sound_pressed.png index 47410d8ea7a9459942728cbbd23d74dbfa1e65c7..d58c7704722a6f6ab7ecea1b997852eb17f4dedf 100644 Binary files a/core/assets/common/_global/application/mainmenu/button_sound_pressed.png and b/core/assets/common/_global/application/mainmenu/button_sound_pressed.png differ diff --git a/core/assets/common/_global/application/mainmenu/button_sound_unpressed.png b/core/assets/common/_global/application/mainmenu/button_sound_unpressed.png index d58c7704722a6f6ab7ecea1b997852eb17f4dedf..47410d8ea7a9459942728cbbd23d74dbfa1e65c7 100644 Binary files a/core/assets/common/_global/application/mainmenu/button_sound_unpressed.png and b/core/assets/common/_global/application/mainmenu/button_sound_unpressed.png differ diff --git a/core/build.gradle b/core/build.gradle index 6894b0f574f4314c8359a5f400ac1954b82a9ea0..5258f8738f969d5fda2ac023c296c2d30fd30b8e 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -35,7 +35,10 @@ task writeTablexiaBuildConfig { "public class TablexiaBuildConfig {\n" + "\n" + " public final static String APP_NAME = \"${tablexiaAppName}\";\n" + - " public final static String VERSION_NAME = \"${tablexiaVersionName}\";\n" + + " public final static String APPLICATION_VERSION_NAME = \"${tablexiaVersionName}\";\n" + + " public final static Integer APPLICATION_VERSION_CODE = ${tablexiaVersionCode};\n" + + " public final static String MODEL_VERSION_NAME = \"${tablexiaModelVersionName}\";\n" + + " public final static Integer MODEL_VERSION_CODE = ${tablexiaModelVersionCode};\n" + " public final static String ASSETS_CHECKSUM = \"${getMapConvertedToString(rootProject.ext.assetsChecksum)}\";\n" + " public final static String TABLEXIA_ASSETS_URL = ${project.hasProperty('TABLEXIA_ASSETS_DOWNLOAD_URL') ? "\"$TABLEXIA_ASSETS_DOWNLOAD_URL\"" : "null"};\n" + " public final static String TABLEXIA_SERVER_PROTOCOL = ${project.hasProperty('TABLEXIA_SERVER_PROTOCOL') ? "\"$TABLEXIA_SERVER_PROTOCOL\"" : "null"};\n" + @@ -43,6 +46,7 @@ task writeTablexiaBuildConfig { " public final static Integer TABLEXIA_SERVER_PORT = ${project.hasProperty('TABLEXIA_SERVER_PORT') ? "$TABLEXIA_SERVER_PORT" : "null"};\n" + " public final static String TABLEXIA_SERVER_SECRET = ${project.hasProperty('TABLEXIA_SERVER_SECRET') ? "\"$TABLEXIA_SERVER_SECRET\"" : "null"};\n" + " public final static String FLURRY_KEY = ${project.hasProperty('TABLEXIA_FLURRY_KEY') ? "\"$TABLEXIA_FLURRY_KEY\"" : "null"};\n" + + " public final static String SENTRY_DSN_FALLBACK = \"${project.sentryDSNFallbackValue}\";\n" + "\n" + "}", BUILD_CONFIG_FILE_ENCODING) } diff --git a/core/external b/core/external index d8cb4a89e64ceec83718fc478f76a5eb31d8fb3e..f1e82e392f631c1e0b9002e41413ddad12b4d4d2 160000 --- a/core/external +++ b/core/external @@ -1 +1 @@ -Subproject commit d8cb4a89e64ceec83718fc478f76a5eb31d8fb3e +Subproject commit f1e82e392f631c1e0b9002e41413ddad12b4d4d2 diff --git a/core/src/cz/nic/tablexia/Tablexia.java b/core/src/cz/nic/tablexia/Tablexia.java index 8b809e02e0f74b8e32716c2bfc85b28fd223db94..636d25d28b9d29c038556bd02fae5f517b355a83 100644 --- a/core/src/cz/nic/tablexia/Tablexia.java +++ b/core/src/cz/nic/tablexia/Tablexia.java @@ -26,6 +26,7 @@ import cz.nic.tablexia.loader.application.ApplicationInternalTextureManager; import cz.nic.tablexia.loader.application.ApplicationTextManager; import cz.nic.tablexia.loader.zip.ZipAssetLoader; import cz.nic.tablexia.menu.MenuController; +import cz.nic.tablexia.model.DatabaseManager; import cz.nic.tablexia.screen.AbstractTablexiaScreen; import cz.nic.tablexia.screen.loader.IConnectionManager; import cz.nic.tablexia.util.Log; @@ -97,12 +98,12 @@ public class Tablexia extends TablexiaApplication { } } - public Tablexia(String buildType, Locale systemLocale, SQLConnectionType sqlConnectionType, IConnectionManager connManager, boolean hasSoftBackButton, boolean reset) { + public Tablexia(String buildType, Locale systemLocale, SQLConnectionType sqlConnectionType, IConnectionManager connManager, String sentryDSN, boolean hasSoftBackButton, boolean reset, String hwSerial) { this.reset = reset; connectionManager = validateConnectionManager(connManager); this.sqlConnectionType = sqlConnectionType; - TablexiaSettings.init(buildType, systemLocale, hasSoftBackButton); + TablexiaSettings.init(buildType, systemLocale, hasSoftBackButton, hwSerial); // register error handler for exceptions in event bus handler methods ApplicationBus.getInstance().addErrorHandler(new IPublicationErrorHandler() { @@ -111,6 +112,12 @@ public class Tablexia extends TablexiaApplication { Log.err(ApplicationBus.class, error.getMessage(), error.getCause()); } }); + + if(TablexiaSettings.getInstance().getBuildType().isBugReport()) { + @SuppressWarnings("ConstantConditions") + String DSN = (TablexiaBuildConfig.SENTRY_DSN_FALLBACK == null || sentryDSN == null || TablexiaBuildConfig.SENTRY_DSN_FALLBACK.equals(sentryDSN)) ? null : sentryDSN; + TablexiaRaven.start(DSN); + } } private void loadingComplete() { @@ -302,9 +309,14 @@ public class Tablexia extends TablexiaApplication { public void create() { super.create(); + TablexiaRaven.sendSavedReports(); + // init data storage TablexiaStorage.init(sqlConnectionType, reset); + // init database + DatabaseManager.initializeDatabase(); + // init dialog factory TablexiaComponentDialogFactory.init(getStage()); diff --git a/core/src/cz/nic/tablexia/TablexiaRaven.java b/core/src/cz/nic/tablexia/TablexiaRaven.java new file mode 100644 index 0000000000000000000000000000000000000000..15f6c330953b1bfbacf9b83946df81eef00786da --- /dev/null +++ b/core/src/cz/nic/tablexia/TablexiaRaven.java @@ -0,0 +1,399 @@ +package cz.nic.tablexia; + +import com.badlogic.gdx.Gdx; +import com.getsentry.raven.DefaultRavenFactory; +import com.getsentry.raven.Raven; +import com.getsentry.raven.connection.Connection; +import com.getsentry.raven.connection.EventSendFailureCallback; +import com.getsentry.raven.dsn.Dsn; +import com.getsentry.raven.event.Event; +import com.getsentry.raven.event.EventBuilder; +import com.getsentry.raven.event.helper.EventBuilderHelper; +import com.getsentry.raven.event.interfaces.ExceptionInterface; +import com.getsentry.raven.event.interfaces.SentryInterface; +import com.getsentry.raven.event.interfaces.StackTraceInterface; + +import net.engio.mbassy.listener.Handler; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import cz.nic.tablexia.bus.ApplicationBus; +import cz.nic.tablexia.game.AbstractTablexiaGame; +import cz.nic.tablexia.loader.TablexiaAbstractFileManager; +import cz.nic.tablexia.screen.AbstractTablexiaScreen; + +/** + * Created by drahomir on 7/28/16. + */ +public class TablexiaRaven { + private static final String EXCEPTION_TYPE_TAG_NAME = "ExceptionType"; + + public enum ExceptionType { + JavaException, + IOSException + } + + /** + * Custom raven factory which allows to set EventSendFailureCallback + */ + private class TablexiaRavenFactory extends DefaultRavenFactory { + private EventSendFailureCallback eventSendFailureCallback; + + public Raven ravenInstance(String DSN, EventSendFailureCallback callback) { + eventSendFailureCallback = callback; + return createRavenInstance(new Dsn(DSN)); + } + + @Override + protected Connection createConnection(Dsn dsn) { + Connection connection = super.createConnection(dsn); + + if(eventSendFailureCallback != null) connection.addEventSendFailureCallback(eventSendFailureCallback); + + return connection; + } + } + + /** + * Type of information to send via raven + */ + private enum InfoType { + TAG { + @Override + protected void insertInfo(TablexiaEventBuilderHelper tablexiaEventBuilderHelper, String name, String value) { + tablexiaEventBuilderHelper.addTag(name, value); + } + }, + EXTRA { + @Override + protected void insertInfo(TablexiaEventBuilderHelper tablexiaEventBuilderHelper, String name, String value) { + tablexiaEventBuilderHelper.addExtra(name, value); + } + }; + + protected void insertInfo(TablexiaEventBuilderHelper tablexiaEventBuilderHelper, String name, String value) {} + } + + /** + * Actual info values to send via raven + */ + private enum Info { + Platform(InfoType.TAG, "Platform", new StringRunnable() { + @Override + public String run() { + return Gdx.app.getType().toString(); + } + }), + Version(InfoType.TAG, "Version", new StringRunnable() { + @Override + public String run() { + return TablexiaBuildConfig.APPLICATION_VERSION_NAME; + } + }), + BuildType(InfoType.TAG, "BuildType", new StringRunnable() { + @Override + public String run() { + return TablexiaSettings.getInstance().getBuildType().toString(); + } + }), + ConnectionType(InfoType.TAG, "ConnectionType", new StringRunnable() { + @Override + public String run() { + return Tablexia.getConnectionManager().getConnectionType().toString(); + } + }), + Language(InfoType.EXTRA, "Language", new StringRunnable() { + @Override + public String run() { + return TablexiaSettings.getInstance().getLocale().toString(); + } + }), + UserInfo(InfoType.EXTRA, "UserInfo", new StringRunnable() { + @Override + public String run() { + return TablexiaSettings.getInstance().getSelectedUser().toString(); + } + }), + UserUUID(InfoType.EXTRA, "UserUUID", new StringRunnable() { + @Override + public String run() { + return TablexiaSettings.getInstance().getSelectedUser().getUuid(); + } + }); + + private static final String DEFAULT_FALLBACK_VALUE = "UNDEFINED"; + + private final InfoType type; + private final String name; + private final String fallBackValue; + private final StringRunnable stringRunnable; + + Info(InfoType type, String name, StringRunnable stringRunnable) { + this(type, name, DEFAULT_FALLBACK_VALUE, stringRunnable); + } + + Info(InfoType type, String name, String fallbackValue, StringRunnable stringRunnable) { + this.type = type; + this.name = name; + this.fallBackValue = fallbackValue; + this.stringRunnable = stringRunnable; + } + + public void insert(TablexiaEventBuilderHelper eventBuilderHelper) { + type.insertInfo(eventBuilderHelper, name, getSafeValue(stringRunnable, fallBackValue)); + } + + private String getSafeValue(StringRunnable runnable, String defaultValue) { + try { + return runnable.run(); + } + catch (Exception e) { + return defaultValue; + } + } + } + + private interface StringRunnable { + //Method which obtains the actual value of Info + String run(); + } + + /** + * Reports Manager - Saves and Resends reports later + */ + private static class ReportsManager extends TablexiaAbstractFileManager { + private static final String REPORT_FILE_EXTENSION = ".TablexiaReport"; + private static final boolean HIDE_REPORT_FILES = true; + + public ReportsManager() { + super(ReportStorageType.EXTERNAL); + } + + public void storeRavenEvent(Event event) { + try { + String fileName = (HIDE_REPORT_FILES ? "." : "") + event.getId().toString() + REPORT_FILE_EXTENSION; + + File dir = TablexiaAbstractFileManager.getFileStoragePathFileHandle(ReportStorageType.EXTERNAL).file(); + if(!dir.exists()) dir.mkdir(); + + File file = new File(dir, fileName); + if(file.exists()) { + file.delete(); + file.createNewFile(); + } + + FileOutputStream fileOut = new FileOutputStream(file); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOut); + objectOutputStream.writeObject(event); + objectOutputStream.close(); + fileOut.close(); + } catch (Exception e) { + e.printStackTrace(); + return; + } + } + + private void sendSavedEvents(TablexiaRaven tablexiaRaven) { + try { + File dir = TablexiaAbstractFileManager.getFileStoragePathFileHandle(ReportStorageType.EXTERNAL).file(); + if(!dir.exists()) return; + + File[] files = dir.listFiles(); + + for(File file : files) { + Event e = deserializeEvent(file); + if(e != null) { + file.delete(); + tablexiaRaven.sendEvent(e); + } + } + } + catch (Exception e) { + e.printStackTrace(); + return; + } + } + + private Event deserializeEvent(File file) { + Event event = null; + + try { + FileInputStream fis = new FileInputStream(file); + ObjectInputStream ois = new ObjectInputStream(fis); + + event = (Event) ois.readObject(); + ois.close(); + fis.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + return event; + } + } + + public class TablexiaEventBuilderHelper implements EventBuilderHelper { + private HashMap<String, String> tablexiaTags; + private HashMap<String, String> tablexiaExtras; + + public TablexiaEventBuilderHelper() { + tablexiaTags = new HashMap<String, String>(); + tablexiaExtras = new HashMap<String, String>(); + } + + public void addTag(String key, String value) { + tablexiaTags.put(key, value); + } + + public void addExtra(String key, String value) { + tablexiaExtras.put(key, value); + } + + public void removeTag(String key) { + if(tablexiaTags.containsKey(key)) + tablexiaTags.remove(key); + } + + public void removeExtra(String key) { + if(tablexiaExtras.containsKey(key)) + tablexiaExtras.remove(key); + } + + @Override + public void helpBuildingEvent(EventBuilder eventBuilder) { + for(Map.Entry<String, String> tag : tablexiaTags.entrySet()) { + eventBuilder.withTag(tag.getKey(), tag.getValue()); + } + + for(Map.Entry<String, String> extra : tablexiaExtras.entrySet()) { + eventBuilder.withExtra(extra.getKey(), extra.getValue()); + } + } + } + + /** + * Actual Raven client + */ + private static final String[] SCREEN_INFO_EVENT_KEYS = new String [] { + AbstractTablexiaGame.RANDOM_SEED_SCREEN_INFO_LABEL, + AbstractTablexiaGame.GAME_DIFFICULTY_SCREEN_INFO_LABEL + }; + + private static TablexiaRaven instance; + + private final EventSendFailureCallback DEFAULT_SEND_EVENT_FAILURE_CALLBACK = new EventSendFailureCallback() { + @Override + public void onFailure(Event event, Exception exception) { + //Calls all registered callbacks + for(EventSendFailureCallback eventSendFailureCallback : sendFailureCallbacks) eventSendFailureCallback.onFailure(event, exception); + } + }; + + private Set<EventSendFailureCallback> sendFailureCallbacks; + private Raven raven; + + private ReportsManager reportsManager; + private TablexiaEventBuilderHelper tablexiaEventBuilderHelper; + + private TablexiaRaven(String DSN) { + this.raven = new TablexiaRavenFactory().ravenInstance(DSN, DEFAULT_SEND_EVENT_FAILURE_CALLBACK); + this.sendFailureCallbacks = new HashSet<EventSendFailureCallback>(); + this.reportsManager = new ReportsManager(); + this.tablexiaEventBuilderHelper = new TablexiaEventBuilderHelper(); + + raven.addBuilderHelper(tablexiaEventBuilderHelper); + + ApplicationBus.getInstance().subscribe(this); + } + + private static boolean isStarted() { + return instance != null; + } + + public static void start(String DSN) { + if(DSN == null || instance != null) return; + + instance = new TablexiaRaven(DSN); + + Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + e.printStackTrace(); + instance.sendExceptionEvent(t, e); + } + }); + + instance.addEventSendFailureCallback(new EventSendFailureCallback() { + @Override + public void onFailure(Event event, Exception exception) { + instance.reportsManager.storeRavenEvent(event); + } + }); + } + + public static void sendSavedReports() { + if(isStarted()) instance.reportsManager.sendSavedEvents(instance); + } + + private void addEventSendFailureCallback(EventSendFailureCallback eventSendFailureCallback) { + if(isStarted()) { + if (eventSendFailureCallback != null) { + if (!sendFailureCallbacks.contains(eventSendFailureCallback)) + sendFailureCallbacks.add(eventSendFailureCallback); + } + } + } + + private void buildAndSendExceptionEvent(String message, SentryInterface sentryInterface, ExceptionType exceptionType) { + EventBuilder eventBuilder = new EventBuilder() + .withMessage(message) + .withSentryInterface(sentryInterface) + .withLevel(Event.Level.ERROR) + .withTag(EXCEPTION_TYPE_TAG_NAME, exceptionType.toString()); + + for(Info info : Info.values()) { + info.insert(tablexiaEventBuilderHelper); + } + + raven.runBuilderHelpers(eventBuilder); + raven.sendEvent(eventBuilder.build()); + Gdx.app.exit(); + } + + private void sendExceptionEvent(Thread t, Throwable e) { + buildAndSendExceptionEvent(e.getMessage(), new ExceptionInterface(e), ExceptionType.JavaException); + } + + public static void sendCustomException(ExceptionType exceptionType, String msg, StackTraceElement[] stackTraceElements) { + if(!isStarted()) return; + instance.buildAndSendExceptionEvent(msg, new StackTraceInterface(stackTraceElements), exceptionType); + } + + private void sendEvent(Event e) { + if(isStarted() && e != null) instance.raven.sendEvent(e); + } + + @Handler + public void handleScreenChangedEvent(TablexiaApplication.ScreenChangedEvent screenChangedEvent) { + for(String infoEventKey : SCREEN_INFO_EVENT_KEYS) { + tablexiaEventBuilderHelper.removeExtra(infoEventKey); + } + } + + @Handler + public void handleScreenInfoEvent(AbstractTablexiaScreen.ScreenInfoEvent screenInfoEvent) { + for(String infoEventKey : SCREEN_INFO_EVENT_KEYS) { + if(infoEventKey.equals(screenInfoEvent.getInfoKey())) { + tablexiaEventBuilderHelper.addExtra(screenInfoEvent.getInfoKey(), screenInfoEvent.getInfoValue()); + } + } + } +} \ No newline at end of file diff --git a/core/src/cz/nic/tablexia/TablexiaSettings.java b/core/src/cz/nic/tablexia/TablexiaSettings.java index 3ecab70b6ba8215c445ef12fe0f3704eb9f39bb6..4360be8638086d72bff9256841d68eedc8e2c6bc 100644 --- a/core/src/cz/nic/tablexia/TablexiaSettings.java +++ b/core/src/cz/nic/tablexia/TablexiaSettings.java @@ -51,12 +51,17 @@ public class TablexiaSettings { //Interval <start month; end month> private static final int WINTER_MODE_START_MONTH = 10; private static final int WINTER_MODE_END_MONTH = 2; - private static boolean winterMode = false; - - private static final String APP_NAME = TablexiaBuildConfig.APP_NAME; - private final String VERSION_NAME = TablexiaBuildConfig.VERSION_NAME; + private static boolean winterMode = false; + + private static final String APP_NAME = TablexiaBuildConfig.APP_NAME; + private final String APPLICATION_VERSION_NAME = TablexiaBuildConfig.APPLICATION_VERSION_NAME; + private final int APPLICATION_VERSION_CODE = TablexiaBuildConfig.APPLICATION_VERSION_CODE; + private final String MODEL_VERSION_NAME = TablexiaBuildConfig.MODEL_VERSION_NAME; + private final int MODEL_VERSION_CODE = TablexiaBuildConfig.MODEL_VERSION_CODE; + private Platform PLATFORM; private final BuildType BUILD_TYPE; private final boolean HAS_SOFT_BACK_BUTTON; + private static String HW_SERIAL_NUMBER; private Preferences preferences; private LocaleDefinition systemLocale; @@ -67,15 +72,47 @@ public class TablexiaSettings { private boolean soundMuted = false; + public enum Platform { + + UNKNOWN (-1, null), + DESKTOP (1, Application.ApplicationType.Desktop), + ANDROID (2, Application.ApplicationType.Android), + iOS (3, Application.ApplicationType.iOS); + + private static Platform FALLBACK_PLATFORM = UNKNOWN; + + private final int id; + private final Application.ApplicationType applicationType; + + Platform(int id, Application.ApplicationType applicationType) { + this.id = id; + this.applicationType = applicationType; + } + + public int getId() { + return id; + } + + public static Platform getPlatformForApplicationType(Application.ApplicationType applicationType) { + for (Platform platform : values()) { + if (platform.applicationType != null && platform.applicationType.equals(applicationType)) { + return platform; + } + } + return FALLBACK_PLATFORM; + } + } + public enum BuildType { // boxes aInfo sInfo dMenu btName bReport debugBtn - RELEASE ("release", false, false, false, false, false, true, false, Log.TablexiaLogLevel.ERROR), - DEBUG ("debug", false, true, true, true, true, true, true, Log.TablexiaLogLevel.DEBUG), - DEVEL ("devel", true, true, true, true, true, false, true, Log.TablexiaLogLevel.DEBUG); + RELEASE (1, "release", false, false, false, false, false, true, false, Log.TablexiaLogLevel.ERROR), + DEBUG (2, "debug", false, true, true, true, true, true, true, Log.TablexiaLogLevel.DEBUG), + DEVEL (3, "devel", true, true, true, true, true, false, true, Log.TablexiaLogLevel.DEBUG); private final static BuildType FALLBACK_VARIANT = BuildType.DEVEL; + private int id; private final String key; private boolean boundingBoxes; private boolean applicationInfo; @@ -86,7 +123,8 @@ public class TablexiaSettings { private boolean showDebugButtons; private final Log.TablexiaLogLevel logLevel; - BuildType(String key, boolean boundingBoxes, boolean applicationInfo, boolean screenInfo, boolean debugMenu, boolean showBuildTypeInName, boolean bugReport, boolean showDebugButtons, Log.TablexiaLogLevel logLevel) { + BuildType(int id, String key, boolean boundingBoxes, boolean applicationInfo, boolean screenInfo, boolean debugMenu, boolean showBuildTypeInName, boolean bugReport, boolean showDebugButtons, Log.TablexiaLogLevel logLevel) { + this.id = id; this.key = key; this.boundingBoxes = boundingBoxes; this.applicationInfo = applicationInfo; @@ -98,6 +136,10 @@ public class TablexiaSettings { this.logLevel = logLevel; } + public int getId() { + return id; + } + public String getKey() { return key; } @@ -164,11 +206,11 @@ public class TablexiaSettings { return instance; } - static void init(String buildTypeKey, Locale systemLocale, boolean hasSoftBackButton) { - TablexiaSettings.init(BuildType.getBuildTypeForKey(buildTypeKey), systemLocale, hasSoftBackButton); + static void init(String buildTypeKey, Locale systemLocale, boolean hasSoftBackButton, String hwSerial) { + TablexiaSettings.init(BuildType.getBuildTypeForKey(buildTypeKey), systemLocale, hasSoftBackButton, hwSerial); } - static void init(BuildType buildType, Locale systemLocale, boolean hasSoftBackButton) { + static void init(BuildType buildType, Locale systemLocale, boolean hasSoftBackButton, String hwSerialNumber) { if (instance != null) { String exceptionMessage = "Tablexia settings already initialized!"; Log.err(TablexiaSettings.class, exceptionMessage); @@ -176,6 +218,7 @@ public class TablexiaSettings { } instance = new TablexiaSettings(buildType, systemLocale, hasSoftBackButton); + TablexiaSettings.HW_SERIAL_NUMBER = hwSerialNumber; } void dispose() { @@ -199,21 +242,44 @@ public class TablexiaSettings { //////////////////////////// SETTINGS ACCESS public String getFullName() { - return getAppName() + " " + getVersionName(); + return getAppName() + " " + getApplicationVersionName(); } public String getAppName() { return getBuildType().getAppName(); } - public String getVersionName() { - return VERSION_NAME; + public String getApplicationVersionName() { + return APPLICATION_VERSION_NAME; + } + + public int getApplicationVersionCode() { + return APPLICATION_VERSION_CODE; + } + + public String getModelVersionName() { + return MODEL_VERSION_NAME; + } + + public int getModelVersionCode() { + return MODEL_VERSION_CODE; + } + + public Platform getPlatform() { + if (PLATFORM == null) { + PLATFORM = Platform.getPlatformForApplicationType(Gdx.app.getType()); + } + return PLATFORM; } public boolean hasSoftBackButton() { return HAS_SOFT_BACK_BUTTON; } + public String getHwSerialNumber() { + return HW_SERIAL_NUMBER; + } + public boolean isWinterMode() { return winterMode; } public boolean isShowBoundingBoxes() { @@ -347,25 +413,26 @@ public class TablexiaSettings { } public enum LocaleDefinition { - - SYSTEM (null, "system", ApplicationTextManager.ApplicationTextsAssets.LANGUAGE_SYSTEM, true), - cs_CZ (new Locale("cs", "CZ"), "cs_CZ", ApplicationTextManager.ApplicationTextsAssets.LANGUAGE_CZECH, true), - sk_SK (new Locale("sk", "SK"), "sk_SK", ApplicationTextManager.ApplicationTextsAssets.LANGUAGE_SLOVAK, true), - de_DE (new Locale("de", "DE"), "de_DE", ApplicationTextManager.ApplicationTextsAssets.LANGUAGE_GERMAN, true); + SYSTEM (null, "system", 0, ApplicationTextManager.ApplicationTextsAssets.LANGUAGE_SYSTEM, true), + cs_CZ (new Locale("cs", "CZ"), "cs_CZ", 1, ApplicationTextManager.ApplicationTextsAssets.LANGUAGE_CZECH, true), + sk_SK (new Locale("sk", "SK"), "sk_SK", 2, ApplicationTextManager.ApplicationTextsAssets.LANGUAGE_SLOVAK, true), + de_DE (new Locale("de", "DE"), "de_DE", 3, ApplicationTextManager.ApplicationTextsAssets.LANGUAGE_GERMAN, true); public final static LocaleDefinition DEFAULT_LOCALE = LocaleDefinition.cs_CZ; private final static LocaleDefinition FALLBACK_VARIANT = LocaleDefinition.SYSTEM; private final Locale locale; private final String localeKey; + private final int localeNumber; private final String descriptionKey; private boolean enabled; private static List<LocaleDefinition> enabledLocaleDefinitions; - LocaleDefinition(Locale locale, String localeKey, String descriptionKey, boolean enabled) { + LocaleDefinition(Locale locale, String localeKey, int localeNumber, String descriptionKey, boolean enabled) { this.locale = locale; this.localeKey = localeKey; + this.localeNumber = localeNumber; this.descriptionKey = descriptionKey; this.enabled = enabled; } @@ -374,6 +441,10 @@ public class TablexiaSettings { return localeKey; } + public int getLocaleNumber() { + return localeNumber; + } + public String getDescriptionKey() { return descriptionKey; } diff --git a/core/src/cz/nic/tablexia/TablexiaStorage.java b/core/src/cz/nic/tablexia/TablexiaStorage.java index 5a56f559b1cf53e55e1be88e2a2e55fd9b1b9212..3e4ebd7e8b2d6914a4466912104cdd76fab5422f 100644 --- a/core/src/cz/nic/tablexia/TablexiaStorage.java +++ b/core/src/cz/nic/tablexia/TablexiaStorage.java @@ -62,7 +62,7 @@ public class TablexiaStorage { Log.err(TablexiaStorage.class, "Cannot create database connection!", e); } } else { - throw new IllegalStateException("Data storage already initialized!"); + Log.info(TablexiaStorage.class, "Data storage has already been initialized! Skipping initialization..."); } } diff --git a/core/src/cz/nic/tablexia/game/AbstractTablexiaGame.java b/core/src/cz/nic/tablexia/game/AbstractTablexiaGame.java index ad20190eacd7e5dae72bbf8bb60b31b83c87dc9f..c29a90f1a6089867ae7c21c1cc515586095577a6 100644 --- a/core/src/cz/nic/tablexia/game/AbstractTablexiaGame.java +++ b/core/src/cz/nic/tablexia/game/AbstractTablexiaGame.java @@ -25,6 +25,7 @@ import net.engio.mbassy.listener.Handler; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; @@ -71,7 +72,6 @@ import cz.nic.tablexia.util.ui.button.TablexiaButton; import cz.nic.tablexia.util.ui.dialog.TablexiaComponentDialog; import cz.nic.tablexia.util.ui.dialog.TablexiaComponentDialogFactory; import cz.nic.tablexia.util.ui.dialog.components.AdaptiveSizeDialogComponent; -import cz.nic.tablexia.util.ui.dialog.components.BackButtonHideComponent; import cz.nic.tablexia.util.ui.dialog.components.CenterPositionDialogComponent; import cz.nic.tablexia.util.ui.dialog.components.DimmerDialogComponent; import cz.nic.tablexia.util.ui.dialog.components.FixedSpaceContentDialogComponent; @@ -215,6 +215,8 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> private ArrayList<TablexiaComponentDialog> receivedTrophyDialogs; private TablexiaComponentDialog victoryDialog; + private RankAnimation rankAnimation; + private LinkedList<ExperienceStar> experienceStars; private static TablexiaButton debugEndGameButton; @@ -589,16 +591,11 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> private final float DIALOG_HEIGHT = 460; private final float DIALOG_WIDTH = 500; - private final float TROPHY_DIALOG_WIDTH = getSceneWidth() * 0.18f; - private final float TROPHY_DIALOG_HEIGHT = TROPHY_DIALOG_WIDTH * 1.2f; + private final float TROPHY_DIALOG_WIDTH = 0.18f; private final int TROPHY_DIALOG_MAX_COUNT = 4; - private final float TROPHY_DIALOG_OFFSET_X = 3f / 10; - private final float TROPHY_DIALOG_GAP_Y = 24; private final float TROPHY_DIALOG_IMAGE_SCALE = 1f; - private final float TROPHY_DIALOG_HORIZONTAL_DEFAULT_PAD = 50; - private final float TROPHY_DIALOG_HORIZONTAL_MOBILE_PAD = 10; - private final float TROPHY_DIALOG_MOBILE_SCALE = 0.7f; - private final float TROPHY_DIALOG_HEIGHT_SCALE = 1.2f; + private final float TROPHY_DIALOG_MOBILE_SCALE = 0.7f; + private final float TROPHY_DIALOG_HEIGHT_SCALE = 1.2f; private static final float VICTORY_DIALOG_TOP_PADDING_HEIGHT_RATIO = 1f / 20; private static final float VICTORY_DIALOG_TITLE_IMAGE_WIDTH_RATIO = 2.5f / 5; @@ -877,6 +874,7 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> @Override public void clicked(InputEvent event, float x, float y) { clearReceivedTrophyDialogs(); + hideVictoryDialogAndStars(); goToGameMenuGamePage(); } }, @@ -922,14 +920,6 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> } }); - adapters.add(new BackButtonHideComponent() { - @Override - protected void hideDialog() { - super.hideDialog(); - backButtonPressed(); - } - }); - //Create the dialog victoryDialog = TablexiaComponentDialogFactory.getInstance().createDialog( adapters.toArray(new TablexiaDialogComponentAdapter[]{})); @@ -989,7 +979,7 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> ); List<ITrophyDefinition> received = new ArrayList<ITrophyDefinition>(); for (ITrophyDefinition trophy : allTrophies) { - if ((!hasTrophies.containsKey(trophy) || hasTrophies.get(trophy) == false) && trophy.hasTrophy(getSelectedUser()) == true) { + if ((!hasTrophies.containsKey(trophy) || !hasTrophies.get(trophy)) && trophy.hasTrophy(getSelectedUser())) { Log.debug(this.getClass(), "has new trophy: " + trophy.getTrophyName()); received.add(trophy); } @@ -1001,7 +991,9 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> } private void showReceivedTrophyDialogs() { + float sceneWidh = TablexiaSettings.getSceneWidth(TablexiaComponentDialogFactory.getDialogStage()); float dialogWidth = isUnderThreshold ? TROPHY_DIALOG_WIDTH * TROPHY_DIALOG_MOBILE_SCALE : TROPHY_DIALOG_WIDTH; + dialogWidth *= sceneWidh; float dialogHeight = dialogWidth * TROPHY_DIALOG_HEIGHT_SCALE; for (TablexiaComponentDialog dialog : receivedTrophyDialogs) { dialog.show(dialogWidth, dialogHeight); @@ -1009,35 +1001,11 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> } private void positionReceivedTrophyDialogs(float dialogX, float dialogY, float dialogWidth, float dialogHeight) { - float dialogPad = isUnderThreshold ? TROPHY_DIALOG_HORIZONTAL_MOBILE_PAD : TROPHY_DIALOG_HORIZONTAL_DEFAULT_PAD; - - int trophyCount = receivedTrophyDialogs.size(); - - int tempCount = trophyCount > (TROPHY_DIALOG_MAX_COUNT/2) ? (TROPHY_DIALOG_MAX_COUNT/2) : trophyCount; - float totalHeight = TROPHY_DIALOG_HEIGHT * tempCount + (tempCount - 1) * TROPHY_DIALOG_GAP_Y; - float startY = dialogY + (dialogHeight - totalHeight)/2f; - float currentHeight = 0; - float x = dialogX + dialogWidth - (TROPHY_DIALOG_WIDTH * TROPHY_DIALOG_OFFSET_X) + dialogPad; - - int dialogNumber = 1; - for (TablexiaComponentDialog dialog : receivedTrophyDialogs) { - if(dialogNumber == (TROPHY_DIALOG_MAX_COUNT/2)+1) { - tempCount = trophyCount - (TROPHY_DIALOG_MAX_COUNT/2); - totalHeight = TROPHY_DIALOG_HEIGHT * tempCount + (tempCount - 1) * TROPHY_DIALOG_GAP_Y; - startY = dialogY + (dialogHeight - totalHeight)/2f; - currentHeight = 0; - x = dialogX - (TROPHY_DIALOG_WIDTH * (1f-TROPHY_DIALOG_OFFSET_X)) - dialogPad; - } - - dialog.setPosition( - x, - startY + currentHeight - ); - - currentHeight += TROPHY_DIALOG_HEIGHT + TROPHY_DIALOG_GAP_Y; - dialogNumber++; - if(dialogNumber > TROPHY_DIALOG_MAX_COUNT) - return; + int trophyCount = receivedTrophyDialogs.size() > TROPHY_DIALOG_MAX_COUNT ? TROPHY_DIALOG_MAX_COUNT : receivedTrophyDialogs.size(); + for (int i = 0; i < trophyCount; i++) { + float x = TrophyDialogPositionDefinition.values()[i].getX(dialogX,dialogWidth, receivedTrophyDialogs.get(i).getInnerWidth(), isUnderThreshold); + float y = TrophyDialogPositionDefinition.values()[i].getY(dialogY,dialogHeight, receivedTrophyDialogs.get(i).getInnerHeight(), isUnderThreshold); + receivedTrophyDialogs.get(i).setPosition(x,y); } } @@ -1063,7 +1031,7 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> screenState.put(HallOfFameScreen.SCROLL_TO_TROPHY_KEY, trophyDefinition.name()); ApplicationBus.getInstance().post(new Tablexia.ChangeScreenEvent(HallOfFameScreen.class, TablexiaApplication.ScreenTransaction.FADE, screenState)).asynchronously(); - victoryDialog.hide(); + hideVictoryDialogAndStars(); clearReceivedTrophyDialogs(); } return false; @@ -1092,17 +1060,26 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> } components.add(new FixedSpaceContentDialogComponent()); - components.add(new BackButtonHideComponent()); TablexiaComponentDialog tcd = TablexiaComponentDialogFactory.getInstance().createDialog( TablexiaComponentDialog.TablexiaDialogType.DIALOG_SQUARE, components.toArray(new TablexiaDialogComponentAdapter[]{})); receivedTrophyDialogs.add(tcd); } - + + private void hideVictoryDialogAndStars() { + if(victoryDialog != null) victoryDialog.hide(); + + if(experienceStars != null) { + for(ExperienceStar star : experienceStars) star.hide(); + } + } + private void clearReceivedTrophyDialogs() { + if(receivedTrophyDialogs == null) return; + for (TablexiaComponentDialog dialog : receivedTrophyDialogs) { - dialog.hide(); + if(dialog != null) dialog.hide(); } receivedTrophyDialogs.clear(); @@ -1118,6 +1095,8 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> } public static class ExperienceStar extends Image { + private static final float FADE_OUT_DURATION = 0.5f; + private Vector2 relativeEndPosition; private ExperienceStarListener listener; @@ -1185,6 +1164,10 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> public void setStarListener(ExperienceStarListener starListener) { this.listener = starListener; } + + public void hide() { + this.addAction(new SequenceAction(Actions.fadeOut(FADE_OUT_DURATION), Actions.removeActor())); + } } private void animateProgressBarAndExperienceStars(Image[] cupsImages, final GameDifficulty gameDifficulty, final UserRankManager.RankProgress rankProgress, final TablexiaProgressBar progressBar) { Vector2 progressBarStagePosition = progressBar.localToStageCoordinates(new Vector2(0, progressBar.getHeight() / 2)); @@ -1193,6 +1176,9 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> int starCountPerCup = gameDifficulty.getExperiencePointsMultiplier(); + if(experienceStars == null) experienceStars = new LinkedList<ExperienceStar>(); + experienceStars.clear(); + //Listener for all stars... final ExperienceStarListener starListener = new ExperienceStarListener() { @Override @@ -1261,13 +1247,15 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> gameRankProgress.setCurrXP(gameRankProgress.getCurrXP() + 1); TablexiaComponentDialogFactory.getDialogStage().addActor(experienceStar); + + experienceStars.add(experienceStar); } } } public void onRankUp(UserRankManager.UserRank previousRank, UserRankManager.UserRank newRank) { final Stage dialogStage = TablexiaComponentDialogFactory.getDialogStage(); - final RankAnimation rankAnimation = RankAnimation.createRankAnimation( + rankAnimation = RankAnimation.createRankAnimation( dialogStage, previousRank, newRank @@ -1303,7 +1291,7 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> private void hideDialogsAndChangeScreen(Class<? extends AbstractTablexiaScreen<?>> screen, TablexiaApplication.ScreenTransaction screenTransaction) { ApplicationBus.getInstance().post(new Tablexia.ChangeScreenEvent(screen, screenTransaction)).asynchronously(); - victoryDialog.hide(); + hideVictoryDialogAndStars(); clearReceivedTrophyDialogs(); } @@ -1388,11 +1376,17 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> //////////////////////////// BACK BUTTON CALLBACK + @Override public void backButtonPressed() { - goToGameMenuGamePage(); + if(rankAnimation != null && !rankAnimation.isHidden()) + rankAnimation.hide(); + else { + hideVictoryDialogAndStars(); + clearReceivedTrophyDialogs(); + goToGameMenuGamePage(); + } } - //////////////////////////// GAME SCORE public <T> void setGameScore(String key, T value) { @@ -1460,4 +1454,38 @@ public abstract class AbstractTablexiaGame<T> extends AbstractTablexiaScreen<T> } return nullValue; } + + enum TrophyDialogPositionDefinition { + + RIGHT_TOP(1,1, 0f, 1.2f, 0.2f, 1f), + RIGHT_BOTTOM(1,0, 0f, 0.3f, 0.2f, 0f), + LEFT_TOP(0,1,1.2f,1.2f, 0.8f, 1f), + LEFT_BOTTOM(0,0, 1.2f,0.3f, 0.8f, 0f); + + private int xStart, yStart; + private float xShift, yShift; + private float mobileShiftX, mobileShiftY; + + TrophyDialogPositionDefinition(int xStart, int yStart, float xShift, float yShift, float mobileShiftX, float mobileShiftY) { + this.xStart = xStart; + this.yStart = yStart; + this.xShift = xShift; + this.yShift = yShift; + this.mobileShiftX = mobileShiftX; + this.mobileShiftY = mobileShiftY; + } + + public float getX(float x, float width, float dialogWidth, boolean isMobile){ + float shift = isMobile ? mobileShiftX : xShift; + return x + width* xStart - shift*dialogWidth; + } + + public float getY(float y, float height, float dialogHeight, boolean isMobile){ + float shift = isMobile ? mobileShiftY : yShift; + return y + height* yStart - shift*dialogHeight; + } + + + } + } \ No newline at end of file diff --git a/core/src/cz/nic/tablexia/game/games/kidnapping/KidnappingGame.java b/core/src/cz/nic/tablexia/game/games/kidnapping/KidnappingGame.java index f7002c74f4d8a57dc9affef093f65670c7dd690f..e2366676396812f32661f87dec452539a3b578b9 100644 --- a/core/src/cz/nic/tablexia/game/games/kidnapping/KidnappingGame.java +++ b/core/src/cz/nic/tablexia/game/games/kidnapping/KidnappingGame.java @@ -210,7 +210,7 @@ public class KidnappingGame extends AbstractTablexiaGame<GameState> { ruleMessageShown = true; } - private void playRuleSound(float delay) { + private void playRuleSound(float delay) { Timer.schedule(new Timer.Task(){ @Override public void run() { diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/PursuitGame.java b/core/src/cz/nic/tablexia/game/games/pursuit/PursuitGame.java index 03d331422c4ef137b7062cae444f34d794247677..a3ce6d2cfb093776e8ff1bf1128376d96307b300 100644 --- a/core/src/cz/nic/tablexia/game/games/pursuit/PursuitGame.java +++ b/core/src/cz/nic/tablexia/game/games/pursuit/PursuitGame.java @@ -3,11 +3,14 @@ package cz.nic.tablexia.game.games.pursuit; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Music; import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.math.CatmullRomSpline; +import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Action; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.actions.Actions; +import com.badlogic.gdx.scenes.scene2d.actions.RunnableAction; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Array; @@ -28,11 +31,11 @@ import cz.nic.tablexia.game.GameDefinition; import cz.nic.tablexia.game.difficulty.GameDifficulty; import cz.nic.tablexia.game.games.pursuit.action.RotateAndMovePieceInPosition; import cz.nic.tablexia.game.games.pursuit.action.RotatePieceToClosestAngle; +import cz.nic.tablexia.game.games.pursuit.action.VehicleMoveAction; import cz.nic.tablexia.game.games.pursuit.assets.PursuitAssets; import cz.nic.tablexia.game.games.pursuit.helper.ArithmeticsHelper; import cz.nic.tablexia.game.games.pursuit.helper.GameRulesHelper; import cz.nic.tablexia.game.games.pursuit.helper.TextureHelper; -import cz.nic.tablexia.game.games.pursuit.listener.VehicleDragListener; import cz.nic.tablexia.game.games.pursuit.model.Grid; import cz.nic.tablexia.game.games.pursuit.model.Maps; import cz.nic.tablexia.game.games.pursuit.model.PuzzlePiece; @@ -119,6 +122,9 @@ public class PursuitGame extends AbstractTablexiaGame<int[][]> { private static final String SCORE_KEY_LAST_MAP = "last_map_index"; private static final float OVERLAP_PIECE_SCALE = 1.2f; + + private static final float ANIMATION_MOVING_DURATION = 5f; + private static final float ANIMATION_DELAY_DURATION = 1.5f; private static final int MAPS_COUNT = Maps.values().length; @@ -149,7 +155,6 @@ public class PursuitGame extends AbstractTablexiaGame<int[][]> { private String clickMapTextureName; private String mapTextureName; - @Override protected Viewport createViewport() { return new ExtendViewport(0, TablexiaSettings.getMinWorldHeight()); @@ -354,7 +359,6 @@ public class PursuitGame extends AbstractTablexiaGame<int[][]> { private void checkEndGameCondition() { if (grid.allPiecesInCorrectPositions() && !gameFinished.get()) { backgroundImage.removeListener(dragAndRotateActorListener); - endGame(); showCheckpoints(); gameFinished.set(true); } @@ -399,26 +403,12 @@ public class PursuitGame extends AbstractTablexiaGame<int[][]> { private void prepareVehicle() { VehicleType vehicleType = TextureHelper.getVehicleTextureName(getRandom(), mapNumber); - Point vehiclePosition = new Point(0, 0); + final Point vehiclePosition = new Point(0, 0); Point vehicleSize = new Point(vehicleType.getVehicleSize().x, vehicleType.getVehicleSize().y); - - Music[] vehicleSounds = getVehicleSounds(vehicleType); - vehicle = new Vehicle(getScreenTextureRegion(vehicleType.getTextureName()), vehiclePosition, vehicleSize); - vehicle.addListener(new VehicleDragListener(vehicle, vehicleSounds, getData(), new Point(roadMap.getWidth(), roadMap.getHeight()), finishFlag, new VehicleDragListener.OnVehicleDragCompleteListener() { - @Override - public void onVehicleDragComplete() { - showGameResultDialog(); - //remove all actor listeners - vehicle.clear(); - vehicle.remove(); - finishFlag.clear(); - finishFlag.remove(); - } - })); vehicle.setDebug(TablexiaSettings.getInstance().isShowBoundingBoxes()); - grid.addActor(vehicle); vehicle.setVisible(false); + grid.addActor(vehicle); } private void prepareFinishFlag() { @@ -426,8 +416,8 @@ public class PursuitGame extends AbstractTablexiaGame<int[][]> { finishFlag.setSize(TextureHelper.FINISH_FLAG_SIZE.x, TextureHelper.FINISH_FLAG_SIZE.y); finishFlag.setOrigin(finishFlag.getWidth() / 2, finishFlag.getHeight() / 2); finishFlag.setDebug(TablexiaSettings.getInstance().isShowBoundingBoxes()); - grid.addActor(finishFlag); finishFlag.setVisible(false); + grid.addActor(finishFlag); } @@ -470,6 +460,7 @@ public class PursuitGame extends AbstractTablexiaGame<int[][]> { //sets the position according to completed map rotation private void showCheckpoints() { Point gridRotationCenter = new Point(grid.getWidth() / 2, grid.getHeight() / 2); + Log.debug(getClass(),"grid rotation: " + grid.getRotation()); //flag Point flagPosition = TextureHelper.getFinishFlagPosition(grid.getWidth(), mapNumber); Point flagPositonConsideringMapRotation = ArithmeticsHelper.translatePositionAccordingToRotation(flagPosition, grid.getRotation(), gridRotationCenter); @@ -484,8 +475,26 @@ public class PursuitGame extends AbstractTablexiaGame<int[][]> { vehicle.setPosition(vehiclePositionConsideringRotation.x - vehicle.getWidth() / 2, vehiclePositionConsideringRotation.y - vehicle.getHeight() / 2); vehicle.setRotation(grid.getRotation()); - vehicle.setVisible(true); finishFlag.setVisible(true); + + final Music[] vehicleSounds = getVehicleSounds( TextureHelper.getVehicleTextureName(getRandom(), mapNumber)); + final CatmullRomSpline<Vector2> path = new CatmullRomSpline<Vector2>(Maps.values()[mapNumber].getPursuitPositionDefinition().getPointsWithRotation(grid.getRotation(), vehiclePosition.x,vehiclePosition.y),false); + VehicleMoveAction vehicleMoveAlongAction = new VehicleMoveAction(path, ANIMATION_MOVING_DURATION, grid.getWidth(), vehicleSounds); + vehicle.addAction(Actions.sequence(Actions.show(),Actions.delay(ANIMATION_DELAY_DURATION),vehicleMoveAlongAction,new RunnableAction() { + @Override + public void run() { + for(Music snd : vehicleSounds) { + snd.stop(); + snd.dispose(); + } + endGame(); + showGameResultDialog(); + vehicle.clear(); + vehicle.remove(); + finishFlag.clear(); + finishFlag.remove(); + } + })); } @Override diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/action/VehicleMoveAction.java b/core/src/cz/nic/tablexia/game/games/pursuit/action/VehicleMoveAction.java new file mode 100644 index 0000000000000000000000000000000000000000..0ca1e5c6d6cc328797273572cf67b92032d3625a --- /dev/null +++ b/core/src/cz/nic/tablexia/game/games/pursuit/action/VehicleMoveAction.java @@ -0,0 +1,57 @@ +package cz.nic.tablexia.game.games.pursuit.action; + +import com.badlogic.gdx.audio.Music; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Path; +import com.badlogic.gdx.math.Vector2; + +import cz.nic.tablexia.util.actions.MoveAlongAction; + +/** + * Created by Vitaliy Vashchenko on 24.6.16. + */ +public class VehicleMoveAction extends MoveAlongAction { + + private float parentSize; + private Path<Vector2> path; + private float duration; + private Music[] vehicleMusic; + private int soundIndex; + public VehicleMoveAction(Path<Vector2> path, float duration, float parentSize, Music[] vehicleMusic) { + super(path, duration); + setRotate(true); + this.path = path; + this.duration = duration; + this.parentSize = parentSize; + this.vehicleMusic = vehicleMusic; + soundIndex = MathUtils.random(0,vehicleMusic.length-1); + } + + + @Override + protected void update(float percent) { + Vector2 value = new Vector2(); + + path.valueAt(value, percent); + + actor.setPosition(parentSize*value.x-actor.getWidth()/2,parentSize*value.y - actor.getHeight()/2); + actor.setRotation(path.derivativeAt(value, percent).angle() - 90); + + } + + + @Override + protected void begin() { + vehicleMusic[soundIndex].setVolume(1); + vehicleMusic[soundIndex].setLooping(true); + vehicleMusic[soundIndex].play(); + super.begin(); + } + + @Override + protected void end() { + vehicleMusic[soundIndex].stop(); + super.end(); + } + +} diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/helper/GameRulesHelper.java b/core/src/cz/nic/tablexia/game/games/pursuit/helper/GameRulesHelper.java index d70a01735e713a1fe6dc7939385eacbeddc0970e..78269d2d949e840dfd0105711e8933679ef2a1fe 100644 --- a/core/src/cz/nic/tablexia/game/games/pursuit/helper/GameRulesHelper.java +++ b/core/src/cz/nic/tablexia/game/games/pursuit/helper/GameRulesHelper.java @@ -74,8 +74,11 @@ public class GameRulesHelper { return durationSeconds * 1000; } - public static AbstractTablexiaGame.GameResult getNumberOfStarsForTime(GameDifficulty difficulty, float millis){ - float seconds = millis/1000; + public static AbstractTablexiaGame.GameResult getNumberOfStarsForTime(GameDifficulty difficulty, Long millis){ + if (millis == null) { + return AbstractTablexiaGame.GameResult.NO_STAR; + } + float seconds = millis / 1000; switch (difficulty) { case EASY: if (seconds > EASY_ONE_STAR_DURATION) { diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/helper/PositionHelper.java b/core/src/cz/nic/tablexia/game/games/pursuit/helper/PositionHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..844eb0c173f6b622a01fa05be36536e1db841420 --- /dev/null +++ b/core/src/cz/nic/tablexia/game/games/pursuit/helper/PositionHelper.java @@ -0,0 +1,96 @@ +package cz.nic.tablexia.game.games.pursuit.helper; + +import com.badlogic.gdx.math.Vector2; + +import cz.nic.tablexia.util.Point; + +/** + * Created by Vitaliy Vashchenko on 20.6.16. + */ +public class PositionHelper { + + enum RotationDefinition { + + ZERO(0f), + LEFT(90f), + UP(270f), + REVERSE(180f); + + float rotation; + + RotationDefinition(float rotation) { + this.rotation = rotation; + } + + public static RotationDefinition getRotationDefinition(float rotation) { + for (RotationDefinition rotationDefinition : RotationDefinition.values()) { + if (rotationDefinition.getRotation() == rotation) return rotationDefinition; + } + return null; + } + + public float getRotation() { + return rotation; + } + } + + public enum PursuitPositionDefinition { + + // TODO: 21.6.16 correct some positions + MAP_1(new Point(0.866f, 0.1f),new Point(0.866f, 0.1f), new Point(0.859f, 0.211f), new Point(0.824f, 0.276f), new Point(0.792f, 0.312f), new Point(0.719f, 0.268f), new Point(0.666f, 0.241f), new Point(0.608f, 0.221f), new Point(0.534f, 0.203f), new Point(0.448f, 0.194f), new Point(0.374f, 0.224f), new Point(0.328f, 0.286f), new Point(0.293f, 0.37f), new Point(0.265f, 0.469f), new Point(0.237f, 0.575f), new Point(0.215f, 0.671f), new Point(0.228f, 0.772f), new Point(0.258f, 0.846f), new Point(0.26f, 0.85f)), + MAP_2(new Point(0.64f, 0.11f),new Point(0.64f, 0.11f), new Point(0.68f, 0.214f), new Point(0.738f, 0.308f), new Point(0.777f, 0.395f), new Point(0.683f, 0.449f), new Point(0.613f, 0.509f), new Point(0.54f, 0.573f), new Point(0.473f, 0.658f), new Point(0.4f, 0.728f), new Point(0.322f, 0.711f), new Point(0.26f, 0.666f), new Point(0.208f, 0.757f), new Point(0.22f, 0.75f)), + MAP_3(new Point(0.08f, 0.41f),new Point(0.08f, 0.41f), new Point(0.182f, 0.461f), new Point(0.271f, 0.466f), new Point(0.368f, 0.475f), new Point(0.376f, 0.599f), new Point(0.387f, 0.698f), new Point(0.398f, 0.755f), new Point(0.361f, 0.824f), new Point(0.394f, 0.868f), new Point(0.461f, 0.877f), new Point(0.531f, 0.85f), new Point(0.627f, 0.897f), new Point(0.691f, 0.899f), new Point(0.77f, 0.903f), new Point(0.776f, 0.855f), new Point(0.758f, 0.811f), new Point(0.776f, 0.754f), new Point(0.79f, 0.71f)), + MAP_4(new Point(0.95f, 0.33f),new Point(0.95f, 0.33f), new Point(0.866f, 0.307f), new Point(0.766f, 0.342f), new Point(0.709f, 0.391f), new Point(0.588f, 0.452f), new Point(0.512f, 0.497f), new Point(0.425f, 0.588f), new Point(0.355f, 0.667f), new Point(0.278f, 0.595f), new Point(0.19f, 0.574f), new Point(0.18f, 0.57f)), + MAP_5(new Point(0.94f, 0.12f),new Point(0.94f, 0.12f), new Point(0.928f, 0.333f), new Point(0.784f, 0.373f), new Point(0.678f, 0.412f), new Point(0.645f, 0.525f), new Point(0.578f, 0.582f), new Point(0.549f, 0.649f), new Point(0.597f, 0.733f), new Point(0.68f, 0.77f), new Point(0.784f, 0.793f), new Point(0.863f, 0.843f), new Point(0.86f, 0.82f)), + MAP_6(new Point(0.95f, 0.17f),new Point(0.95f, 0.17f), new Point(0.85f, 0.18f), new Point(0.763f, 0.171f), new Point(0.68f, 0.136f), new Point(0.602f, 0.092f), new Point(0.538f, 0.036f), new Point(0.509f, 0.081f), new Point(0.438f, 0.077f), new Point(0.392f, 0.142f), new Point(0.369f, 0.199f), new Point(0.377f, 0.251f), new Point(0.436f, 0.306f), new Point(0.45f, 0.32f)), + MAP_7(new Point(0.56f, 0.07f),new Point(0.56f, 0.07f), new Point(0.43f, 0.16f), new Point(0.347f, 0.246f), new Point(0.373f, 0.36f), new Point(0.443f, 0.465f), new Point(0.499f, 0.58f), new Point(0.431f, 0.657f), new Point(0.379f, 0.738f), new Point(0.356f, 0.825f), new Point(0.36f, 0.83f)), + MAP_8(new Point(0.16f, 0.19f),new Point(0.16f, 0.19f), new Point(0.237f, 0.255f), new Point(0.287f, 0.316f), new Point(0.351f, 0.354f), new Point(0.285f, 0.44f), new Point(0.212f, 0.521f), new Point(0.134f, 0.597f), new Point(0.071f, 0.679f), new Point(0.118f, 0.718f), new Point(0.204f, 0.754f), new Point(0.272f, 0.733f), new Point(0.343f, 0.798f), new Point(0.425f, 0.856f), new Point(0.496f, 0.919f), new Point(0.596f, 0.853f), new Point(0.672f, 0.823f), new Point(0.759f, 0.82f), new Point(0.818f, 0.828f), new Point(0.825f, 0.801f), new Point(0.83f, 0.79f)), + MAP_9(new Point(0.15f, 0.11f),new Point(0.15f, 0.11f), new Point(0.193f, 0.179f), new Point(0.255f, 0.19f), new Point(0.164f, 0.426f), new Point(0.234f, 0.494f), new Point(0.307f, 0.661f), new Point(0.356f, 0.723f), new Point(0.435f, 0.776f), new Point(0.509f, 0.805f), new Point(0.622f, 0.831f), new Point(0.719f, 0.837f), new Point(0.808f, 0.834f), new Point(0.81f, 0.83f)), + MAP_10(new Point(0.22f, 0.07f),new Point(0.22f, 0.07f), new Point(0.214f, 0.293f), new Point(0.204f, 0.421f), new Point(0.449f, 0.422f), new Point(0.574f, 0.561f), new Point(0.678f, 0.49f), new Point(0.806f, 0.75f), new Point(0.761f, 0.838f), new Point(0.76f, 0.84f)), + MAP_11(new Point(0.61f, 0.11f),new Point(0.61f, 0.11f), new Point(0.582f, 0.258f), new Point(0.571f, 0.364f), new Point(0.599f, 0.442f), new Point(0.641f, 0.499f), new Point(0.646f, 0.584f), new Point(0.702f, 0.626f), new Point(0.81f, 0.644f), new Point(0.801f, 0.693f), new Point(0.678f, 0.683f), new Point(0.553f, 0.688f), new Point(0.366f, 0.697f), new Point(0.302f, 0.688f), new Point(0.214f, 0.697f), new Point(0.21f, 0.69f)), + MAP_12(new Point(0.89f, 0.17f),new Point(0.89f, 0.17f), new Point(0.806f, 0.118f), new Point(0.565f, 0.111f), new Point(0.43f, 0.102f), new Point(0.385f, 0.164f), new Point(0.436f, 0.294f), new Point(0.473f, 0.442f), new Point(0.492f, 0.562f), new Point(0.444f, 0.676f), new Point(0.385f, 0.792f), new Point(0.278f, 0.803f), new Point(0.223f, 0.843f), new Point(0.208f, 0.868f), new Point(0.2f, 0.85f)), + MAP_13(new Point(0.08f, 0.06f),new Point(0.08f, 0.06f), new Point(0.189f, 0.227f), new Point(0.414f, 0.316f), new Point(0.665f, 0.51f), new Point(0.797f, 0.632f), new Point(0.88f, 0.735f), new Point(0.88f, 0.73f)), + MAP_14(new Point(0.18f, 0.08f),new Point(0.18f, 0.08f), new Point(0.212f, 0.239f), new Point(0.29f, 0.321f), new Point(0.399f, 0.382f), new Point(0.342f, 0.503f), new Point(0.311f, 0.659f), new Point(0.308f, 0.773f), new Point(0.324f, 0.843f), new Point(0.32f, 0.84f)); + + private Point[] points; + + PursuitPositionDefinition(Point... points) { + this.points = points; + } + + public Point[] getPoints() { + return points; + } + + public Vector2[] getPointsWithRotation(float rotation, float x, float y) { + RotationDefinition rotationDefinition = RotationDefinition.getRotationDefinition(rotation); + Vector2[] rotatedPositions = new Vector2[points.length]; + + for (int i = 0; i < getPoints().length; i++) { + rotatedPositions[i] = getRotatedPosition(rotationDefinition, getPoints()[i]); + } + + return rotatedPositions; + } + + private Vector2 getRotatedPosition(RotationDefinition rotationDefinition, Point position) { + //TODO - Refactor (Added null check, cos it caused crashing on my Nexus 5X) + if(rotationDefinition == null) return new Vector2(position.x, position.y); + + switch (rotationDefinition) { + case UP: + //x = y, y = 1-x + return new Vector2(position.y, 1 - position.x); + case LEFT: + //x=1-y, y=x + return new Vector2(1 - position.y, position.x); + case REVERSE: + //x = 1-x,y=1-y + return new Vector2(1 - position.x, 1 - position.y); + default: + return new Vector2(position.x, position.y); + } + } + } + +} diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/listener/VehicleDragListener.java b/core/src/cz/nic/tablexia/game/games/pursuit/listener/VehicleDragListener.java deleted file mode 100644 index 6ad2c04988d17f77cdb3ffcc2c3b9537c248ee96..0000000000000000000000000000000000000000 --- a/core/src/cz/nic/tablexia/game/games/pursuit/listener/VehicleDragListener.java +++ /dev/null @@ -1,135 +0,0 @@ -package cz.nic.tablexia.game.games.pursuit.listener; - -import com.badlogic.gdx.audio.Music; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.InputEvent; - -import cz.nic.tablexia.game.games.pursuit.helper.ArithmeticsHelper; -import cz.nic.tablexia.util.MusicUtil; -import cz.nic.tablexia.util.Point; -import cz.nic.tablexia.game.games.pursuit.model.Vehicle; -import cz.nic.tablexia.util.listener.DragActorListener; - -/** - * Created by Václav TarantĂk on 10.8.15. - */ -public class VehicleDragListener extends DragActorListener implements Music.OnCompletionListener{ - private static final int POINTS_CACHE_SIZE = 5; - private Point[] touchedPointsCache; - private int currentTouchPointCacheElementPointer; - private int[][] roadColorData; - private Point roadMapSize; - private Actor goalActor; - private OnVehicleDragCompleteListener onVehicleDragCompleteListener; - private final float moveTolerance; - - private Music[] sounds; - - private boolean playingSounds = false; - private int currentSoundIndex = 0; - - //goalActor is the actor that marks the finish of the vehicle path, here finish flag - public VehicleDragListener(Actor actor, Music[] sounds, int[][] roadColorData, Point roadMapSize, Actor goalActor, OnVehicleDragCompleteListener onVehicleDragCompleteListener) { - super(actor); - this.sounds = sounds; - this.roadColorData = roadColorData; - this.roadMapSize = roadMapSize; - this.goalActor = goalActor; - this.onVehicleDragCompleteListener = onVehicleDragCompleteListener; - touchedPointsCache = new Point[POINTS_CACHE_SIZE]; - // vehicle move tolerance is two times size of bigger side of vehicle (width / height of actor) - moveTolerance = 2 * Math.max(actor.getWidth(), actor.getHeight()); - } - - @Override - public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { - touchedPointsCache[currentTouchPointCacheElementPointer] = new Point(x, y); - playingSounds = true; - - sounds[currentSoundIndex].setVolume(1); - sounds[currentSoundIndex].play(); - sounds[currentSoundIndex].setOnCompletionListener(this); - return super.touchDown(event, x, y, pointer, button); - } - - @Override - public void touchDragged(InputEvent event, float x, float y, int pointer) { - Vector2 recalculatedCoords = new Vector2(x, y); - actor.localToParentCoordinates(recalculatedCoords); - Point touchPoint = new Point(recalculatedCoords.x, recalculatedCoords.y); - if (isPointOnMap(touchPoint)) { - Color touchedColor = getTouchedColor(recalculatedCoords.x, recalculatedCoords.y); - if (touchedColor.r == 1 && touchedColor.a == 1) { - currentTouchPointCacheElementPointer = (currentTouchPointCacheElementPointer + 1) % touchedPointsCache.length; - touchedPointsCache[currentTouchPointCacheElementPointer] = new Point(recalculatedCoords.x, recalculatedCoords.y); - if (currentTouchPointCacheElementPointer == POINTS_CACHE_SIZE - 1) { - actor.setRotation((float) ArithmeticsHelper.getAngleBetweenTwoPoints(touchedPointsCache[0], touchedPointsCache[touchedPointsCache.length - 1])); - } - - double distance = Math.hypot(touchPoint.x - actor.getX(), touchPoint.y - actor.getY()); - - // finger or cursor is too far from vehicle to move it - if (distance > moveTolerance) { - return; - } - - super.touchDragged(event, x, y, pointer); - if (((Vehicle) actor).intersectsWith(goalActor)) { - onVehicleDragCompleteListener.onVehicleDragComplete(); - - for(Music snd : sounds) { - snd.stop(); - snd.dispose(); - } - } - } - } - } - - @Override - public void touchUp(InputEvent event, float x, float y, int pointer, int button) { - playingSounds = false; - - if(sounds[currentSoundIndex].isPlaying()) { - MusicUtil.fadeOut(sounds[currentSoundIndex], 0.5f, false); - } - - super.touchUp(event, x, y, pointer, button); - } - - - @Override - public void onCompletion(Music music) { - if(!playingSounds) - return; - - currentSoundIndex++; - - if(currentSoundIndex >= sounds.length) - currentSoundIndex = 0; - - sounds[currentSoundIndex].setVolume(1); - sounds[currentSoundIndex].play(); - sounds[currentSoundIndex].setOnCompletionListener(this); - } - - private Color getTouchedColor(float x, float y) { - Point mapRotationCenter = new Point(actor.getParent().getWidth() / 2, actor.getParent().getHeight() / 2); - Point pointOnRotatedMap = ArithmeticsHelper.translatePositionAccordingToRotation(new Point(x, y), 360 - actor.getParent().getRotation(), mapRotationCenter); - float clickX = (pointOnRotatedMap.x / actor.getParent().getWidth() * roadMapSize.x); - float clickY = roadMapSize.y - (pointOnRotatedMap.y / actor.getParent().getHeight() * roadMapSize.y); - Point clickedPoint = new Point(clickX, clickY); - - return new Color(roadColorData[(int) clickedPoint.x][(int) (clickedPoint.y)]); - } - - private boolean isPointOnMap(Point p) { - return ((p.x >= 0) && (p.x <= actor.getParent().getWidth()) && (p.y >= 0) && (p.y <= actor.getParent().getHeight())); - } - - public interface OnVehicleDragCompleteListener { - void onVehicleDragComplete(); - } -} diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/model/Maps.java b/core/src/cz/nic/tablexia/game/games/pursuit/model/Maps.java index fb9f77cc82c7f427120052ad52f0778c02cb0ed2..6407a0a507ae5d10e7e84be6224b7c905744bfac 100644 --- a/core/src/cz/nic/tablexia/game/games/pursuit/model/Maps.java +++ b/core/src/cz/nic/tablexia/game/games/pursuit/model/Maps.java @@ -1,36 +1,40 @@ package cz.nic.tablexia.game.games.pursuit.model; +import cz.nic.tablexia.game.games.pursuit.helper.PositionHelper; import cz.nic.tablexia.util.Point; /** * Created by Václav TarantĂk on 10.8.15. */ public enum Maps { - - MAP1("map1", new Point(0.866f, 0.1f), new Point(0.26f, 0.85f)), - MAP2("map2", new Point(0.64f, 0.11f), new Point(0.22f, 0.75f)), - MAP3("map3", new Point(0.08f, 0.41f), new Point(0.79f, 0.71f)),// TODO add car initial rotation - MAP4("map4", new Point(0.95f, 0.33f), new Point(0.18f, 0.57f)), - MAP5("map5", new Point(0.94f, 0.12f), new Point(0.86f, 0.82f)), - MAP6("map6", new Point(0.95f, 0.17f), new Point(0.45f, 0.32f)), - MAP7("map7", new Point(0.56f, 0.07f), new Point(0.36f, 0.83f)), - MAP8("map8", new Point(0.16f, 0.19f), new Point(0.83f, 0.79f)), - MAP9("map9", new Point(0.15f, 0.11f), new Point(0.81f, 0.83f)), - MAP10("map10", new Point(0.22f, 0.07f), new Point(0.76f, 0.84f)), - MAP11("map11", new Point(0.61f, 0.11f), new Point(0.21f, 0.69f)), - MAP12("map12", new Point(0.89f, 0.17f), new Point(0.2f, 0.85f)), - MAP13("map13", new Point(0.08f, 0.06f), new Point(0.88f, 0.73f)), - MAP14("map14", new Point(0.18f, 0.08f), new Point(0.32f, 0.84f)); + // TODO add car initial rotation + MAP1("map1", new Point(0.866f, 0.1f), new Point(0.26f, 0.85f), PositionHelper.PursuitPositionDefinition.MAP_1), + MAP2("map2", new Point(0.64f, 0.11f), new Point(0.22f, 0.75f), PositionHelper.PursuitPositionDefinition.MAP_2), + MAP3("map3", new Point(0.08f, 0.41f), new Point(0.79f, 0.71f), PositionHelper.PursuitPositionDefinition.MAP_3), + MAP4("map4", new Point(0.95f, 0.33f), new Point(0.18f, 0.57f), PositionHelper.PursuitPositionDefinition.MAP_4), + MAP5("map5", new Point(0.94f, 0.12f), new Point(0.86f, 0.82f), PositionHelper.PursuitPositionDefinition.MAP_5), + MAP6("map6", new Point(0.95f, 0.17f), new Point(0.45f, 0.32f), PositionHelper.PursuitPositionDefinition.MAP_6), + MAP7("map7", new Point(0.56f, 0.07f), new Point(0.36f, 0.83f), PositionHelper.PursuitPositionDefinition.MAP_7), + MAP8("map8", new Point(0.16f, 0.19f), new Point(0.83f, 0.79f), PositionHelper.PursuitPositionDefinition.MAP_8), + MAP9("map9", new Point(0.15f, 0.11f), new Point(0.81f, 0.83f), PositionHelper.PursuitPositionDefinition.MAP_9), + MAP10("map10", new Point(0.22f, 0.07f), new Point(0.76f, 0.84f),PositionHelper.PursuitPositionDefinition.MAP_10), + MAP11("map11", new Point(0.61f, 0.11f), new Point(0.21f, 0.69f),PositionHelper.PursuitPositionDefinition.MAP_11), + MAP12("map12", new Point(0.89f, 0.17f), new Point(0.2f, 0.85f),PositionHelper.PursuitPositionDefinition.MAP_12), + MAP13("map13", new Point(0.08f, 0.06f), new Point(0.88f, 0.73f),PositionHelper.PursuitPositionDefinition.MAP_13), + MAP14("map14", new Point(0.18f, 0.08f), new Point(0.32f, 0.84f),PositionHelper.PursuitPositionDefinition.MAP_14); private String textureRegionName; //relatives position of checkpoints on map private Point startPointCoords; private Point endPointCoords; + + private PositionHelper.PursuitPositionDefinition pursuitPositionDefinition; - Maps(String textureRegionName, Point startPointCoords, Point endPointCoords){ + Maps(String textureRegionName, Point startPointCoords, Point endPointCoords, PositionHelper.PursuitPositionDefinition positionDefinition){ this.textureRegionName = textureRegionName; this.startPointCoords = startPointCoords; this.endPointCoords = endPointCoords; + this.pursuitPositionDefinition = positionDefinition; } public String getTextureRegionName(){ @@ -44,4 +48,8 @@ public enum Maps { public cz.nic.tablexia.util.Point getEndPointCoords(){ return endPointCoords; } + + public PositionHelper.PursuitPositionDefinition getPursuitPositionDefinition() { + return pursuitPositionDefinition; + } } diff --git a/core/src/cz/nic/tablexia/game/ranksystem/RankAnimation.java b/core/src/cz/nic/tablexia/game/ranksystem/RankAnimation.java index ca7ffb14e3373cac0edf71935d71403016a1a817..1fb4e131ccafe6780f736118ed6e1914d08894b6 100644 --- a/core/src/cz/nic/tablexia/game/ranksystem/RankAnimation.java +++ b/core/src/cz/nic/tablexia/game/ranksystem/RankAnimation.java @@ -63,6 +63,8 @@ public class RankAnimation extends Group { private final Group shinesGroup; private final UserRankManager.UserRank oldRank, newRank; + private boolean hidden = true; + private RankAnimation(float width, float height, UserRankManager.UserRank oldRank, UserRankManager.UserRank newRank) { setSize(width, height); this.oldRank = oldRank; @@ -213,6 +215,8 @@ public class RankAnimation extends Group { //////////////////////////////// public void hide() { + hidden = true; + this.addAction(new SequenceAction( Actions.fadeOut(HIDE_FADEOUT_DURATION), Actions.removeActor() @@ -221,9 +225,11 @@ public class RankAnimation extends Group { public void show() { if(getStage() == null) { - Log.err(getClass(), "Couldn't show Rank Animation, because there is not stage!"); + Log.err(getClass(), "Couldn't show Rank Animation, because there is no stage!"); } + hidden = false; + this.addAction(new SequenceAction( Actions.fadeIn(SHOW_FADEIN_DURATION), Actions.run(new Runnable() { @@ -235,6 +241,10 @@ public class RankAnimation extends Group { )); } + public boolean isHidden() { + return hidden; + } + public void setNewBadgeEventListener(EventListener eventListener) { if(eventListener == null) return; diff --git a/core/src/cz/nic/tablexia/game/ranksystem/UserRankManager.java b/core/src/cz/nic/tablexia/game/ranksystem/UserRankManager.java index 1d2fa996518f2cfa90f4390ea16c92ca4ead0240..f2e536e200ca7aa010dc7fbbbb9eb14ad803b7d5 100644 --- a/core/src/cz/nic/tablexia/game/ranksystem/UserRankManager.java +++ b/core/src/cz/nic/tablexia/game/ranksystem/UserRankManager.java @@ -192,7 +192,7 @@ public class UserRankManager { RankProgress[] result = gameRankProgressMap.get(user.getId()); if(result == null) { - refreshUserRank(user); + forceRefreshUserRank(user); result = gameRankProgressMap.get(user.getId()); } @@ -206,7 +206,7 @@ public class UserRankManager { RankProgress[] result = gameRankProgressMap.get(user.getId()); if(result == null) { - refreshUserRank(user); + forceRefreshUserRank(user); result = gameRankProgressMap.get(user.getId()); } diff --git a/core/src/cz/nic/tablexia/loader/TablexiaAbstractFileManager.java b/core/src/cz/nic/tablexia/loader/TablexiaAbstractFileManager.java index 85aa2f34ed7b25173ea473a3a3fee77a06f83000..95fea3edcac45e459af49dd9427d26657009ea56 100644 --- a/core/src/cz/nic/tablexia/loader/TablexiaAbstractFileManager.java +++ b/core/src/cz/nic/tablexia/loader/TablexiaAbstractFileManager.java @@ -163,6 +163,30 @@ public abstract class TablexiaAbstractFileManager extends AssetManager { } } + public enum ReportStorageType implements StorageType { + + INTERNAL(RootStorageType.INTERNAL, ReportStorageType.REPORTS_DIRECTORY), + EXTERNAL(RootStorageType.LOCAL, ReportStorageType.REPORTS_DIRECTORY); + + public static final String REPORTS_DIRECTORY = "reports/"; + + private String storagePath; + private FileHandleResolver resolver; + + ReportStorageType(RootStorageType rootStorageType, String assetsPath) { + this.storagePath = rootStorageType.getStoragePath() + assetsPath; + this.resolver = rootStorageType.getResolver(); + } + + public String getStoragePath() { + return storagePath; + } + + public FileHandleResolver getResolver() { + return resolver; + } + } + public static FileHandle getFileStoragePathFileHandle(StorageType storageType, String additionalPath) { return storageType.getResolver().resolve(storageType.getStoragePath() + additionalPath); } diff --git a/core/src/cz/nic/tablexia/menu/AbstractMenu.java b/core/src/cz/nic/tablexia/menu/AbstractMenu.java index 3c82418f808c58a239f6106e35d476dc33262262..ef157ea9bb1b864a0b6008a5cc0c7b2ed65faebc 100644 --- a/core/src/cz/nic/tablexia/menu/AbstractMenu.java +++ b/core/src/cz/nic/tablexia/menu/AbstractMenu.java @@ -42,7 +42,8 @@ import cz.nic.tablexia.util.ui.TablexiaNoBlendingImage; * @author Matyáš Latner */ public abstract class AbstractMenu extends Stack implements Disposable { - private static final String VERSION_LINE_SEPARATOR = "\r\n"; + + private static final String TABLEXIA_VERSION_LABEL = "%s\r\n%s"; protected enum MenuControlType { @@ -314,7 +315,7 @@ public abstract class AbstractMenu extends Stack implements Disposable { //App name and version TablexiaLabel appName = new TablexiaLabel( - TablexiaSettings.getInstance().getAppName() + VERSION_LINE_SEPARATOR + TablexiaSettings.getInstance().getVersionName(), + String.format(TABLEXIA_VERSION_LABEL, TablexiaSettings.getInstance().getAppName(), TablexiaSettings.getInstance().getApplicationVersionName()), new TablexiaLabel.TablexiaLabelStyle(APP_NAME_TEXT_FONT, Color.BLACK)); appName.setAlignment(APP_NAME_TEXT_ALIGN); appName.setWrap(true); diff --git a/core/src/cz/nic/tablexia/menu/main/MainMenu.java b/core/src/cz/nic/tablexia/menu/main/MainMenu.java index f30cec98b62d1ef89eab79f7709652a2447359f6..1c64acaef709dadda94e5599bf4ee36340a18305 100644 --- a/core/src/cz/nic/tablexia/menu/main/MainMenu.java +++ b/core/src/cz/nic/tablexia/menu/main/MainMenu.java @@ -79,7 +79,7 @@ public class MainMenu extends AbstractMenu { menuItemContainer.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { - if(inTapSquare(x, y)) performMenuAction(menuItem); + performMenuAction(menuItem); } }); menuItemsLayout.addActor(menuItemContainer); @@ -94,7 +94,7 @@ public class MainMenu extends AbstractMenu { submenuItemContainer.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { - if(inTapSquare(x, y)) performMenuAction(submenuItem); + performMenuAction(submenuItem); } }); subMenuLayout.addActor(submenuItemContainer); diff --git a/core/src/cz/nic/tablexia/menu/user/UserMenu.java b/core/src/cz/nic/tablexia/menu/user/UserMenu.java index 0333213fc68479638febf24d6d6f970814be3433..7a22d759eefbbe3c1863c4b63bb19737044648f1 100644 --- a/core/src/cz/nic/tablexia/menu/user/UserMenu.java +++ b/core/src/cz/nic/tablexia/menu/user/UserMenu.java @@ -31,18 +31,17 @@ import cz.nic.tablexia.sync.work.DownloadUser; import cz.nic.tablexia.sync.work.PushDataToServer; import cz.nic.tablexia.sync.work.SyncWork; import cz.nic.tablexia.util.ui.ClickListenerWithSound; -import cz.nic.tablexia.util.ui.dialog.TablexiaComponentDialog; import cz.nic.tablexia.util.ui.dialog.TablexiaComponentDialogFactory; import cz.nic.tablexia.util.ui.dialog.components.AdaptiveSizeDialogComponent; import cz.nic.tablexia.util.ui.dialog.components.BackButtonHideComponent; import cz.nic.tablexia.util.ui.dialog.components.CenterPositionDialogComponent; import cz.nic.tablexia.util.ui.dialog.components.DimmerDialogComponent; import cz.nic.tablexia.util.ui.dialog.components.FixedSpaceContentDialogComponent; +import cz.nic.tablexia.util.ui.dialog.components.PositiveNegativeButtonContentDialogComponent; import cz.nic.tablexia.util.ui.dialog.components.ResizableSpaceContentDialogComponent; import cz.nic.tablexia.util.ui.dialog.components.TextContentDialogComponent; import cz.nic.tablexia.util.ui.dialog.components.TextFiledDialogComponent; import cz.nic.tablexia.util.ui.dialog.components.ViewportMaximumSizeComponent; -import cz.nic.tablexia.util.ui.dialog.components.PositiveNegativeButtonContentDialogComponent; /** * UserMenu container @@ -56,10 +55,14 @@ public class UserMenu extends AbstractMenu { private static final int USER_ITEM_HEIGHT = 80; private static final float DOWNLOAD_DIALOG_INPUT_WIDTH_PERCENT = 0.8f; - private static final int SYNC_REQUEST_DIALOG_WIDTH = 450; - private static final int SYNC_REQUEST_DIALOG_HEIGHT = 300; - private static final String SYNC_REQUEST_DIALOG_PLACEHOLDER_TEXT = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; - private static final int SYNC_REQUEST_DIALOG_MAXIMUM_LENGTH = 40; + private static final int SYNC_REQUEST_DIALOG_WIDTH = 450; + private static final int SYNC_REQUEST_DIALOG_HEIGHT = 300; + private static final String SYNC_REQUEST_DIALOG_PLACEHOLDER_TEXT = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; + private static final int SYNC_REQUEST_DIALOG_MAXIMUM_LENGTH = 36; + private static final float SYNC_DIALOG_TITLE_PAD = 0.15f; + private static final float SYNC_DIALOG_TEXT_FIELD_PAD = 0.05f; + + public static final String CODE_REGEX = "(([0-9]|[a-f]){8})-(([0-9]|[a-f]){4})-(([0-9]|[a-f]){4})-(([0-9]|[a-f]){4})-(([0-9]|[a-f]){12})$"; private List<User> users; @@ -156,23 +159,25 @@ public class UserMenu extends AbstractMenu { new DimmerDialogComponent(), new ViewportMaximumSizeComponent(), new AdaptiveSizeDialogComponent(), - new ResizableSpaceContentDialogComponent(), + new FixedSpaceContentDialogComponent(SYNC_DIALOG_TITLE_PAD), new TextContentDialogComponent(ApplicationTextManager.getInstance().getText(ApplicationTextManager.ApplicationTextsAssets.SYNC_REQUEST_DIALOG_TEXT)), - new ResizableSpaceContentDialogComponent(), + new FixedSpaceContentDialogComponent(SYNC_DIALOG_TEXT_FIELD_PAD), textFiledDialogComponent, new ResizableSpaceContentDialogComponent(), new PositiveNegativeButtonContentDialogComponent(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { super.clicked(event, x, y); - DownloadUser syncWork = new DownloadUser(textFiledDialogComponent.getText()); - syncWork.registerListener(new SyncWork.RestSyncListener() { - @Override - public void onSuccess(User user) { - ApplicationBus.getInstance().post(new RefreshUserMenu()).asynchronously(); - } - }); - RestSynchronizationService.doSyncWork(syncWork); + if (textFiledDialogComponent.getText().length()>0 && textFiledDialogComponent.getText().toLowerCase().matches(CODE_REGEX)) { + DownloadUser syncWork = new DownloadUser(textFiledDialogComponent.getText()); + syncWork.registerListener(new SyncWork.RestSyncListener() { + @Override + public void onSuccess(User user) { + ApplicationBus.getInstance().post(new RefreshUserMenu()).asynchronously(); + } + }); + RestSynchronizationService.doSyncWork(syncWork); + } //Prevents keyboard getting stuck Gdx.input.setOnscreenKeyboardVisible(false); } diff --git a/core/src/cz/nic/tablexia/model/DatabaseManager.java b/core/src/cz/nic/tablexia/model/DatabaseManager.java new file mode 100644 index 0000000000000000000000000000000000000000..ed7d5a54cae4218b4c11cdf8859907569b6ece25 --- /dev/null +++ b/core/src/cz/nic/tablexia/model/DatabaseManager.java @@ -0,0 +1,225 @@ +package cz.nic.tablexia.model; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import cz.nic.tablexia.TablexiaStorage; +import cz.nic.tablexia.shared.model.Game; +import cz.nic.tablexia.util.Log; + +/** + * Created by drahomir on 6/14/16. + */ +public class DatabaseManager { + private interface VersionScriptExecutor { + void executeVersionScript(TablexiaStorage storage, VersionScript versionScript) throws SQLException; + } + + private static final VersionScriptExecutor DEFAULT_SCRIPT_EXECUTOR = new VersionScriptExecutor() { + @Override + public void executeVersionScript(TablexiaStorage storage, VersionScript versionScript) throws SQLException { + Statement statement = storage.createStatement(); + statement.execute(versionScript.sqlStatement); + statement.close(); + } + }; + + private enum VersionScript { + VERSION_01( 1, "ALTER TABLE game ADD locale INTEGER NOT NULL DEFAULT " + Game.DEFAULT_GAME_LOCALE), + VERSION_02( 2, "ALTER TABLE game ADD application_version_name TEXT NOT NULL DEFAULT '" + Game.DEFAULT_APPLICATION_VERSION_NAME + "'"), + VERSION_03( 3, "ALTER TABLE game ADD application_version_code INTEGER NOT NULL DEFAULT " + Game.DEFAULT_APPLICATION_VERSION_CODE), + VERSION_04( 4, "ALTER TABLE game ADD model_version_name TEXT NOT NULL DEFAULT '" + Game.DEFAULT_MODEL_VERSION_NAME + "'"), + VERSION_05( 5, "ALTER TABLE game ADD model_version_code INTEGER NOT NULL DEFAULT " + Game.DEFAULT_MODE_VERSION_CODE), + VERSION_06( 6, "ALTER TABLE game ADD build_type INTEGER NOT NULL DEFAULT " + Game.DEFAULT_BUILD_TYPE), + VERSION_07( 7, "ALTER TABLE game ADD platform INTEGER NOT NULL DEFAULT " + Game.DEFAULT_PLATFORM), + VERSION_08( 8, "ALTER TABLE game ADD hw_serial_number TEXT"); + + private int version; + private String sqlStatement; + private VersionScriptExecutor versionScriptExecutor; + + VersionScript(int version, String sqlStatement) { + this.version = version; + this.sqlStatement = sqlStatement; + this.versionScriptExecutor = DEFAULT_SCRIPT_EXECUTOR; + } + + VersionScript(int version, String sqlStatement, VersionScriptExecutor versionScriptExecutor) { + this.version = version; + this.sqlStatement = sqlStatement; + this.versionScriptExecutor = versionScriptExecutor; + } + + public void execute(TablexiaStorage storage) throws SQLException{ + versionScriptExecutor.executeVersionScript(storage, this); + } + + /** + * Gets all version scripts newer than the current version (current version not included) + * @param version + * @return + */ + public static List<VersionScript> getVersionScriptsFromVersion(int version) { + List<VersionScript> versionScripts = new ArrayList<VersionScript>(); + + for(VersionScript script : VersionScript.values()) { + if(script.version > version) versionScripts.add(script); + } + + Collections.sort(versionScripts, new Comparator<VersionScript>() { + @Override + public int compare(VersionScript o1, VersionScript o2) { + return o1.version - o2.version; + } + }); + + return versionScripts; + } + + public static int getLastVersion() { + int max = Integer.MIN_VALUE; + + for(VersionScript script : VersionScript.values()) { + if(script.version > max) + max = script.version; + } + + return max; + } + } + + private static final int INITIAL_DATABASE_VERSION = 0; + + public static final String CREATE_TABLE_DATABASE_VERSION = "CREATE TABLE IF NOT EXISTS dbversion (version INTEGER NOT NULL DEFAULT " + INITIAL_DATABASE_VERSION + ")"; + public static final String INSERT_DATABASE_VERSION = "INSERT INTO dbversion(version) VALUES(?)"; + public static final String SELECT_DATABASE_VERSION = "SELECT max(version) FROM dbversion"; + public static final String SELECT_DATABASE_VERSION_ALL = "SELECT version FROM dbversion"; //Used to find out if there is any database version + + public static final String UPDATE_DATABASE_VERSION = "UPDATE dbversion SET version = ?"; + + private static final void convertDatabase() throws SQLException { + int dbVersion = getDatabaseVersion(); + + List<VersionScript> versionScripts = VersionScript.getVersionScriptsFromVersion(dbVersion); + + if(versionScripts.isEmpty()) { + Log.info(DatabaseManager.class, "Version database is actual!"); + return; + } + + try { + Log.info(DatabaseManager.class, "Current database version is: " + dbVersion + ". Converting database to version: " + VersionScript.getLastVersion()); + + TablexiaStorage.getInstance().setAutoCommit(false); + + for (VersionScript currVersionScript : versionScripts) { + Log.info(DatabaseManager.class, "Executing version script: " + currVersionScript); + currVersionScript.execute(TablexiaStorage.getInstance()); //Execute the script + } + + Log.info(DatabaseManager.class, "All version scripts were executed successfully, committing changes!"); + TablexiaStorage.getInstance().commit(); + TablexiaStorage.getInstance().setAutoCommit(true); + + //Update DB version + updateDatabaseVersion(VersionScript.getLastVersion()); + } + catch (SQLException e) { + //Something went wrong, rollbaaaack! + TablexiaStorage.getInstance().rollback(); + e.printStackTrace(); + } + } + + public static final void initializeDatabase() { + try { + Statement statement = TablexiaStorage.getInstance().createStatement(); + statement.execute(CREATE_TABLE_DATABASE_VERSION); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + + if(!hasDatabaseVersion()) + insertInitialDatabaseVersion(); + + try { + convertDatabase(); + } catch (SQLException e) { + throw new IllegalStateException("Couldn't migrate database to actual version. Reason: " + e.getMessage(), e); + } + } + + private static final void updateDatabaseVersion(int version) { + try { + PreparedStatement statement = TablexiaStorage.getInstance().prepareStatement(UPDATE_DATABASE_VERSION); + statement.setInt(1, version); + statement.execute(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private static final void insertInitialDatabaseVersion() { + Log.info(DatabaseManager.class, "Inserting initial database version into DB!"); + + try { + PreparedStatement statement = TablexiaStorage.getInstance().prepareStatement(INSERT_DATABASE_VERSION); + statement.setInt(1, INITIAL_DATABASE_VERSION); + statement.execute(); + statement.close(); + } catch (SQLException e) { + Log.err(Game.class, "Cannot insert database version into DB!", e); + } + } + + private static final boolean hasDatabaseVersion() { + try { + PreparedStatement statement = TablexiaStorage.getInstance().prepareStatement(SELECT_DATABASE_VERSION_ALL); + + //Get result + ResultSet resultSet = statement.executeQuery(); + + boolean result = resultSet.next(); + + //Clean + statement.close(); + resultSet.close(); + + return result; + } catch (SQLException e) { + Log.err(Game.class, "Cannot get database version from DB!", e); + } + return false; + } + + private static final int getDatabaseVersion () { + try { + PreparedStatement statement = TablexiaStorage.getInstance().prepareStatement(SELECT_DATABASE_VERSION); + statement.execute(); + + //Get result + ResultSet resultSet = statement.executeQuery(); + if(!resultSet.next()) throw new SQLException(); + + int result = resultSet.getInt(1); + + //Clean + statement.close(); + resultSet.close(); + + return result; + } catch (SQLException e) { + Log.err(Game.class, "Cannot get database version from DB!", e); + } + + throw new IllegalStateException("Cannot get database version!"); + } +} \ No newline at end of file diff --git a/core/src/cz/nic/tablexia/model/UserDAO.java b/core/src/cz/nic/tablexia/model/UserDAO.java index 1898b43e10671ea9eeba1f8ebfc938c31b805272..b3c91a7cf52f909273a9244ca415dd09d7cf0a0e 100644 --- a/core/src/cz/nic/tablexia/model/UserDAO.java +++ b/core/src/cz/nic/tablexia/model/UserDAO.java @@ -4,9 +4,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import cz.nic.tablexia.TablexiaStorage; import cz.nic.tablexia.bus.ApplicationBus; @@ -242,7 +240,7 @@ public class UserDAO { continue; } - Long gameId = GameDAO.importGame(dbUser, game.getGameDifficulty(), game.getGameNumber(), game.getRandomSeed(), game.getStartTime(), game.getEndTime()); + Long gameId = GameDAO.importGame(dbUser, game); if (gameId == null) { continue; @@ -296,5 +294,4 @@ public class UserDAO { private CreatedUserEvent() { } } - -} +} \ No newline at end of file diff --git a/core/src/cz/nic/tablexia/model/game/GameDAO.java b/core/src/cz/nic/tablexia/model/game/GameDAO.java index fa89fbaa3d2dbc10b5e0e52cfa3e7b73a62f8ebd..85ff15797cd522f7641d9124fd7b94ccb49af925 100644 --- a/core/src/cz/nic/tablexia/model/game/GameDAO.java +++ b/core/src/cz/nic/tablexia/model/game/GameDAO.java @@ -28,8 +28,10 @@ import cz.nic.tablexia.util.Log; */ public class GameDAO { - private static final Object ATOMIC_LOCK = new Object(); - private static final AtomicInteger gameScoreSetCounter = new AtomicInteger(0); + private static final Object ATOMIC_LOCK = new Object(); + private static final String STRING_ONLY_DIGITS_REGEX = "[0-9]+"; + + private static final AtomicInteger gameScoreSetCounter = new AtomicInteger(0); //////////////////////////// Game API @@ -37,7 +39,7 @@ public class GameDAO { Game game = null; Long id = insertNewGame(user, difficulty, gameDefinition, random); if (id != null) { - game = new Game(id, user, difficulty.getDifficultyNumber(), gameDefinition.getGameNumber(), random.getSeed()); + game = GameDAO.selectGameForId(id); game.setGamePauses(GamePauseDAO.selectGamePausesForGame(game)); } return game; @@ -145,28 +147,59 @@ public class GameDAO { //////////////////////////// DB ACCESS + public static final String GAME_SELECT_COLUMNS = "id, user_id, difficulty_number, game_number, random_seed, start_time, end_time, locale, application_version_name, application_version_code, model_version_name, model_version_code, build_type, platform, hw_serial_number"; + + public static Game prepareGameObject(ResultSet resultSet) throws SQLException { + Game game = new Game( + resultSet.getLong(1), //gameId + UserDAO.selectUser(resultSet.getLong(2)), //user + resultSet.getInt(3), //difficultyNumber + resultSet.getInt(4), //gameNumber + resultSet.getLong(5), //randomSeed + prepareLong(resultSet.getString(6)), //startTime + prepareLong(resultSet.getString(7)), //endTime + resultSet.getInt(8), //locale + resultSet.getString(9), //applicationVersionName + resultSet.getInt(10), //applicationVersionCode + resultSet.getString(11), //modelVersionName + resultSet.getInt(12), //modelVersionCode + resultSet.getInt(13), //buildType + resultSet.getInt(14), //platform + resultSet.getString(15) //hwSerialNumber + ); + game.setGamePauses(GamePauseDAO.selectGamePausesForGame(game)); + game.getGameScoreMap().addAll(GameScoreDAO.selectGameScores(game.getId())); + return game; + } + + private static Long prepareLong(String longNumber) { + if (longNumber != null && longNumber.matches(STRING_ONLY_DIGITS_REGEX)) { + return Long.valueOf(longNumber); + } + return null; + } + // prepared statements public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS game (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, start_time INTEGER, end_time INTEGER, difficulty_number INTEGER NOT NULL, game_number INTEGER NOT NULL, random_seed INTEGER NOT NULL, sync_at INTEGER, FOREIGN KEY(user_id) REFERENCES user(id))"; - public static final String NEW_GAME_INSERT = "INSERT INTO game (user_id, difficulty_number, game_number, random_seed) VALUES (?, ?, ?, ?)"; + public static final String NEW_GAME_INSERT = "INSERT INTO game (user_id, difficulty_number, game_number, random_seed, locale, application_version_name, application_version_code, model_version_name, model_version_code, build_type, platform, hw_serial_number) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; public static final String GAME_UPDATE_START = "UPDATE game SET start_time = ? WHERE id = ?"; public static final String GAME_UPDATE_END = "UPDATE game SET end_time = ? WHERE id = ?"; public static final String GAME_UPDATE_SYNC_AT = "UPDATE game SET sync_at = ? WHERE id = ?"; - public static final String GAME_SELECT_FOR_ID = "SELECT id, user_id, difficulty_number, game_number, random_seed, start_time, end_time FROM game WHERE id = ?"; + public static final String GAME_SELECT_FOR_ID = "SELECT " + GAME_SELECT_COLUMNS + " FROM game WHERE id = ?"; public static final String GAME_SELECT_LAST_ID = "SELECT max(id) FROM game"; public static final String GAME_SELECT_COUNT_FOR_GAME_AND_DIFFICULTY = "SELECT count(id) FROM game WHERE game_number = ? AND difficulty_number = ? AND user_id = ? AND end_time IS NOT NULL"; - public static final String GAME_SELECT_FOR_USER_AND_DEFINITION = "SELECT id, user_id, difficulty_number, game_number, random_seed, start_time, end_time FROM game WHERE user_id = ? AND game_number = ? AND end_time IS NOT NULL AND end_time != 0 ORDER BY start_time ASC"; + public static final String GAME_SELECT_FOR_USER_AND_DEFINITION = "SELECT " + GAME_SELECT_COLUMNS + " FROM game WHERE user_id = ? AND game_number = ? AND end_time IS NOT NULL AND end_time != 0 ORDER BY start_time ASC"; public static final String GAME_SELECT_COUNT_FOR_GAME = "SELECT count(id) FROM game WHERE game_number = ? AND user_id = ?"; - public static final String GAME_SELECT_ALL_FOR_USER_SYNC = "SELECT id, user_id, difficulty_number, game_number, random_seed, start_time, end_time FROM game where user_id = ? AND sync_at is null"; - + public static final String GAME_SELECT_ALL_FOR_USER_SYNC = "SELECT " + GAME_SELECT_COLUMNS + " FROM game where user_id = ? AND sync_at is null"; public static final String GAME_SELECT_BY_START_AND_END = "SELECT id FROM game WHERE user_id = ? AND start_time = ? AND end_time = ?"; public static final String GAME_SELECT_BY_START_AND_NULL_END = "SELECT id FROM game WHERE user_id = ? AND start_time = ? AND end_time IS NULL"; public static final String GAME_SELECT_LAST_SCORES_FOR_USER_AND_GAME = "SELECT value FROM game_score INNER JOIN game ON game_score.game_id=game.id AND game.user_id=? AND game.game_number=? WHERE game_score.key=? AND end_time IS NOT NULL ORDER BY game_id DESC LIMIT 1"; - public static final String GAME_SELECT_FOR_RANK_MANAGER = "SELECT id, difficulty_number, game_number, start_time, end_time FROM game WHERE user_id = ? AND start_time IS NOT NULL AND start_time != 0 AND end_time IS NOT NULL AND end_time != 0 ORDER BY end_time ASC"; + public static final String GAME_SELECT_FOR_RANK_MANAGER = "SELECT " + GAME_SELECT_COLUMNS + " FROM game WHERE user_id = ? AND start_time IS NOT NULL AND start_time != 0 AND end_time IS NOT NULL AND end_time != 0 ORDER BY end_time ASC"; // classic statements - public static final String IMPORT_GAME_INSERT = "INSERT INTO game (user_id, difficulty_number, game_number, random_seed, start_time, end_time, sync_at) VALUES (%d, %d, %d, %d, %d, %s, %d)"; + public static final String IMPORT_GAME_INSERT = "INSERT INTO game (user_id, difficulty_number, game_number, random_seed, start_time, end_time, locale, application_version_name, application_version_code, model_version_name, model_version_code, build_type, platform, hw_serial_number, sync_at) VALUES (%d, %d, %d, %d, %s, %s, %d, '%s', %d, '%s', %d, %d, %d, '%s', %d)"; private static Long insertNewGame(User user, GameDifficulty difficulty, GameDefinition gameDefinition, TablexiaRandom random) { @@ -176,6 +209,14 @@ public class GameDAO { insertStatement.setInt(2, difficulty.getDifficultyNumber()); insertStatement.setInt(3, gameDefinition.getGameNumber()); insertStatement.setLong(4, random.getSeed()); + insertStatement.setInt(5, TablexiaSettings.getInstance().getLocaleDefinition().getLocaleNumber()); + insertStatement.setString(6, TablexiaSettings.getInstance().getApplicationVersionName()); + insertStatement.setInt(7, TablexiaSettings.getInstance().getApplicationVersionCode()); + insertStatement.setString(8, TablexiaSettings.getInstance().getModelVersionName()); + insertStatement.setInt(9, TablexiaSettings.getInstance().getModelVersionCode()); + insertStatement.setInt(10, TablexiaSettings.getInstance().getBuildType().getId()); + insertStatement.setInt(11, TablexiaSettings.getInstance().getPlatform().getId()); + insertStatement.setString(12, TablexiaSettings.getInstance().getHwSerialNumber()); insertStatement.executeUpdate(); insertStatement.close(); // insertStatement.getGeneratedKeys().getLong(1) cannot be used -> getGeneratedKeys() is not implemented in SQLDroid @@ -208,13 +249,29 @@ public class GameDAO { return result; } - public static Long importGame(User user, int difficulty, int gameNumber, long randomSeed, long startTime, long endTime) { + public static Long importGame(User user, Game game) { try { Long gameId = null; Statement st = TablexiaStorage.getInstance().createStatement(); + Long startTime = game.getStartTime(); + Long endTime = game.getEndTime(); // workaround for sync error -> serialized JSON from server contains 0 instead of NULL -// String sql = String.format(IMPORT_GAME_INSERT, user.getId(), difficulty, gameNumber, randomSeed, startTime, endTime, System.currentTimeMillis()); - String sql = String.format(IMPORT_GAME_INSERT, user.getId(), difficulty, gameNumber, randomSeed, startTime, endTime != 0 ? String.valueOf(endTime) : "NULL", System.currentTimeMillis()); + String sql = String.format(IMPORT_GAME_INSERT, + user.getId(), + game.getGameDifficulty(), + game.getGameNumber(), + game.getRandomSeed(), + startTime != 0 ? String.valueOf(startTime) : "NULL", + endTime != 0 ? String.valueOf(endTime) : "NULL", + game.getGameLocale(), + game.getApplicationVersionName(), + game.getApplicationVersionCode(), + game.getModelVersionName(), + game.getModelVersionCode(), + game.getBuildType(), + game.getPlatform(), + game.getHwSerialNumber(), + System.currentTimeMillis()); st.executeUpdate(sql); gameId = selectLastGameId(); st.close(); @@ -227,16 +284,16 @@ public class GameDAO { return null; } - public static Long selectGameByTimes(long userId, long startTime, long endTime) throws SQLException { + public static Long selectGameByTimes(long userId, long startTime, Long endTime) throws SQLException { // workaround for sync error -> serialized JSON from server contains 0 instead of NULL // PreparedStatement statement = TablexiaStorage.getInstance().prepareStatement(GAME_SELECT_BY_START_AND_END); - PreparedStatement statement = TablexiaStorage.getInstance().prepareStatement(endTime != 0 ? GAME_SELECT_BY_START_AND_END : GAME_SELECT_BY_START_AND_NULL_END); + PreparedStatement statement = TablexiaStorage.getInstance().prepareStatement((endTime != null && endTime != 0) ? GAME_SELECT_BY_START_AND_END : GAME_SELECT_BY_START_AND_NULL_END); statement.setLong(1, userId); statement.setLong(2, startTime); // workaround for sync error -> serialized JSON from server contains 0 instead of NULL // statement.setLong(3, endTime); - if (endTime != 0) { + if (endTime != null && endTime != 0) { statement.setLong(3, endTime); } @@ -259,18 +316,7 @@ public class GameDAO { try { ResultSet resultSet = statement.executeQuery(); if (resultSet.next()) { - String startTimeStr = resultSet.getString(6); - String endTimeStr = resultSet.getString(7); - selectedGame = new Game(resultSet.getLong(1), - UserDAO.selectUser(resultSet.getLong(2)), - resultSet.getInt(3), - resultSet.getInt(4), - resultSet.getLong(5), - startTimeStr != null ? Long.valueOf(startTimeStr) : null, - endTimeStr != null ? Long.valueOf(endTimeStr) : null); - - selectedGame.setGamePauses(GamePauseDAO.selectGamePausesForGame(selectedGame)); - selectedGame.getGameScoreMap().addAll(GameScoreDAO.selectGameScores(selectedGame.getId())); + selectedGame = prepareGameObject(resultSet); } resultSet.close(); } catch (SQLException e) { @@ -291,19 +337,7 @@ public class GameDAO { try { ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { - String startTimeStr = resultSet.getString(6); - String endTimeStr = resultSet.getString(7); - Game game = new Game(resultSet.getLong(1), - UserDAO.selectUser(resultSet.getLong(2)), - resultSet.getInt(3), - resultSet.getInt(4), - resultSet.getLong(5), - startTimeStr != null ? Long.valueOf(startTimeStr) : null, - endTimeStr != null ? Long.valueOf(endTimeStr) : null); - - game.setGamePauses(GamePauseDAO.selectGamePausesForGame(game)); - game.getGameScoreMap().addAll(GameScoreDAO.selectGameScores(game.getId())); - games.add(game); + games.add(prepareGameObject(resultSet)); } resultSet.close(); } catch (SQLException e) { @@ -325,29 +359,8 @@ public class GameDAO { ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { - long id = resultSet.getLong(1); - int diff = resultSet.getInt(2); - int gameNum = resultSet.getInt(3); - String startTime = resultSet.getString(4); - String endTime = resultSet.getString(5); - - Long startTimeLong = startTime != null ? Long.valueOf(startTime) : null; - Long endTimeLong = endTime != null ? Long.valueOf(endTime) : null; - - if(startTime == null || endTime == null) continue; //only game that were finished - - Game game = new Game( - id, - UserDAO.selectUser(userId), - diff, - gameNum, - 0L, - startTimeLong, - endTimeLong - ); - - game.setGamePauses(GamePauseDAO.selectGamePausesForGame(game)); - game.getGameScoreMap().addAll(GameScoreDAO.selectGameScores(game.getId())); + Game game = prepareGameObject(resultSet); + if(game.getStartTime() == null || game.getEndTime() == null) continue; //only games that were finished games.add(game); } resultSet.close(); @@ -376,22 +389,7 @@ public class GameDAO { while (hasNextGames) { if (resultSet.next()) { - Game game; - - String startTimeStr = resultSet.getString(6); - String endTimeStr = resultSet.getString(7); - game = new Game(resultSet.getLong(1), - UserDAO.selectUser(resultSet.getLong(2)), - resultSet.getInt(3), - resultSet.getInt(4), - resultSet.getLong(5), - startTimeStr != null ? Long.valueOf(startTimeStr) : null, - endTimeStr != null ? Long.valueOf(endTimeStr) : null); - - game.setGamePauses(GamePauseDAO.selectGamePausesForGame(game)); - game.getGameScoreMap().addAll(GameScoreDAO.selectGameScores(game.getId())); - selectedGames.add(game); - + selectedGames.add(prepareGameObject(resultSet)); } else { hasNextGames = false; } diff --git a/core/src/cz/nic/tablexia/model/game/GameTrophy.java b/core/src/cz/nic/tablexia/model/game/GameTrophy.java index 9980d2eb4d12ea549a1c6114282dd655040a25d7..0c3925b3c594d4b1a6830ea8f2e0d5a960248dd6 100644 --- a/core/src/cz/nic/tablexia/model/game/GameTrophy.java +++ b/core/src/cz/nic/tablexia/model/game/GameTrophy.java @@ -10,7 +10,6 @@ import cz.nic.tablexia.TablexiaStorage; import cz.nic.tablexia.game.AbstractTablexiaGame; import cz.nic.tablexia.game.difficulty.GameDifficulty; import cz.nic.tablexia.game.trophy.GameTrophyDefinition; -import cz.nic.tablexia.model.UserDAO; import cz.nic.tablexia.shared.model.User; import cz.nic.tablexia.shared.model.Game; import cz.nic.tablexia.util.Log; @@ -55,7 +54,7 @@ public class GameTrophy { public static class ThreeStarsReceived implements GameTrophyResolver { - public static final String GAME_SELECT_FOR_GAME_AND_DIFFICULTY = "SELECT id, user_id, difficulty_number, game_number, random_seed, start_time, end_time FROM game WHERE game_number = ? AND difficulty_number = ? AND user_id = ? AND end_time IS NOT NULL"; + public static final String GAME_SELECT_FOR_GAME_AND_DIFFICULTY = "SELECT " + GameDAO.GAME_SELECT_COLUMNS + " FROM game WHERE game_number = ? AND difficulty_number = ? AND user_id = ? AND end_time IS NOT NULL"; private static List<Game> getGamesForGameAndDifficulty(User user, GameTrophyDefinition trophyDef) { List<Game> games = new ArrayList<Game>(); @@ -67,18 +66,7 @@ public class GameTrophy { try { ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { - String startTimeStr = resultSet.getString(6); - String endTimeStr = resultSet.getString(7); - Game game = new Game(resultSet.getLong(1), - UserDAO.selectUser(resultSet.getLong(2)), - resultSet.getInt(3), - resultSet.getInt(4), - resultSet.getLong(5), - startTimeStr != null ? Long.valueOf(startTimeStr) : null, - endTimeStr != null ? Long.valueOf(endTimeStr) : null); - game.setGamePauses(GamePauseDAO.selectGamePausesForGame(game)); - game.getGameScoreMap().addAll(GameScoreDAO.selectGameScores(game.getId())); - games.add(game); + games.add(GameDAO.prepareGameObject(resultSet)); } resultSet.close(); } catch (SQLException e) { diff --git a/core/src/cz/nic/tablexia/model/game/UserTrophy.java b/core/src/cz/nic/tablexia/model/game/UserTrophy.java index e35c953e4a7d2a970b7fef3f4f4874056d15403e..9a007361d6659e3d6cd1dbddb331e27bb4413894 100644 --- a/core/src/cz/nic/tablexia/model/game/UserTrophy.java +++ b/core/src/cz/nic/tablexia/model/game/UserTrophy.java @@ -20,9 +20,8 @@ import cz.nic.tablexia.game.AbstractTablexiaGame; import cz.nic.tablexia.game.GameDefinition; import cz.nic.tablexia.game.difficulty.GameDifficulty; import cz.nic.tablexia.game.trophy.UserTrophyDefinition; -import cz.nic.tablexia.model.UserDAO; -import cz.nic.tablexia.shared.model.User; import cz.nic.tablexia.shared.model.Game; +import cz.nic.tablexia.shared.model.User; import cz.nic.tablexia.util.Log; /** @@ -37,7 +36,7 @@ public class UserTrophy { public static class AllGamesInOneDay implements UserTrophyResolver { - public static final String ALL_IN_ONE_DAY_SELECT = "SELECT game_number, end_time FROM game WHERE user_id = ? AND end_time IS NOT NULL"; + public static final String ALL_IN_ONE_DAY_SELECT = "SELECT game_number, end_time FROM game WHERE user_id = ? AND end_time IS NOT NULL AND difficulty_number != 0"; @Override public boolean hasGameTrophy(User user, UserTrophyDefinition trophyDef) { @@ -155,8 +154,8 @@ public class UserTrophy { public static class AllStarsGame implements UserTrophyResolver { - public static final String GAME_SELECT_FOR_USER_AND_DIFFICULTY = "SELECT id, user_id, difficulty_number, game_number, random_seed, start_time, end_time FROM game WHERE difficulty_number = ? AND user_id = ? AND end_time IS NOT NULL"; - public static final String GAME_SELECT_FOR_USER = "SELECT id, user_id, difficulty_number, game_number, random_seed, start_time, end_time FROM game WHERE user_id = ? AND difficulty_number != ? AND start_time IS NOT NULL AND start_time != 0 AND end_time IS NOT NULL AND end_time != 0"; + public static final String GAME_SELECT_FOR_USER_AND_DIFFICULTY = "SELECT " + GameDAO.GAME_SELECT_COLUMNS + " FROM game WHERE difficulty_number = ? AND user_id = ? AND end_time IS NOT NULL"; + public static final String GAME_SELECT_FOR_USER = "SELECT " + GameDAO.GAME_SELECT_COLUMNS + " FROM game WHERE user_id = ? AND difficulty_number != ? AND start_time IS NOT NULL AND start_time != 0 AND end_time IS NOT NULL AND end_time != 0"; private static List<Game> getGamesForUserAndDifficulty(User user, UserTrophyDefinition trophyDef) throws SQLException { PreparedStatement statement = TablexiaStorage.getInstance().prepareStatement(GAME_SELECT_FOR_USER_AND_DIFFICULTY); @@ -180,19 +179,7 @@ public class UserTrophy { try { ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { - String startTimeStr = resultSet.getString(6); - String endTimeStr = resultSet.getString(7); - Game game = new Game(resultSet.getLong(1), - UserDAO.selectUser(resultSet.getLong(2)), - resultSet.getInt(3), - resultSet.getInt(4), - resultSet.getLong(5), - startTimeStr != null ? Long.valueOf(startTimeStr) : null, - endTimeStr != null ? Long.valueOf(endTimeStr) : null); - - game.setGamePauses(GamePauseDAO.selectGamePausesForGame(game)); - game.getGameScoreMap().addAll(GameScoreDAO.selectGameScores(game.getId())); - games.add(game); + games.add(GameDAO.prepareGameObject(resultSet)); } resultSet.close(); } catch (SQLException e) { diff --git a/core/src/cz/nic/tablexia/screen/AbstractTablexiaScreen.java b/core/src/cz/nic/tablexia/screen/AbstractTablexiaScreen.java index 867faca89a52ff11659699eb445f582cede1a642..87027a4d8e0f99393b51b8d09880d23c3d636ce3 100644 --- a/core/src/cz/nic/tablexia/screen/AbstractTablexiaScreen.java +++ b/core/src/cz/nic/tablexia/screen/AbstractTablexiaScreen.java @@ -198,6 +198,8 @@ public abstract class AbstractTablexiaScreen<T> extends ScreenAdapter { private boolean loadAsync; private TablexiaAbstractFileManager.AssetsStorageType storageType; + private boolean backButtonAllowed = false; + private Map<String, TablexiaMusic> notDisposedMusics; private static class TextManager extends TablexiaDataManager<I18NBundle> { @@ -583,6 +585,8 @@ public abstract class AbstractTablexiaScreen<T> extends ScreenAdapter { private final void performScreenLoaded() { Log.info(getClass(), "[ ------- Screen Loaded ------- ]"); + backButtonAllowed = false; + // reset screen state after loading screen with state TablexiaStorage.getInstance().resetScreenState(this); @@ -602,6 +606,8 @@ public abstract class AbstractTablexiaScreen<T> extends ScreenAdapter { screenVisible(screenState); performScreenResumed(); playIntroMusic(); + + backButtonAllowed = true; } private final void performScreenResized(int width, int height) { @@ -772,7 +778,7 @@ public abstract class AbstractTablexiaScreen<T> extends ScreenAdapter { public void backButtonPressed(TablexiaApplication.BackButtonPressed event) { if (event.shouldProcess(TablexiaApplication.BackButtonPressed.SCREEN_PRIORITY)) { event.setProcessWithPriority(TablexiaApplication.BackButtonPressed.SCREEN_PRIORITY); - if (loadingComplete && getClass().equals(TablexiaApplication.getActualScreenClass())) { + if (loadingComplete && backButtonAllowed && getClass().equals(TablexiaApplication.getActualScreenClass())) { backButtonPressed(); } } diff --git a/core/src/cz/nic/tablexia/screen/encyclopedia/EncyclopediaScreen.java b/core/src/cz/nic/tablexia/screen/encyclopedia/EncyclopediaScreen.java index caa657e076222d8f13eae993ccf5ce3042105296..10e409729d2c428f732237eae47b6f1658cf0582 100644 --- a/core/src/cz/nic/tablexia/screen/encyclopedia/EncyclopediaScreen.java +++ b/core/src/cz/nic/tablexia/screen/encyclopedia/EncyclopediaScreen.java @@ -14,6 +14,8 @@ import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.viewport.ExtendViewport; import com.badlogic.gdx.utils.viewport.Viewport; +import net.engio.mbassy.listener.Handler; + import java.util.List; import java.util.Map; @@ -375,4 +377,9 @@ public class EncyclopediaScreen extends AbstractTablexiaScreen<Void> { } super.screenDisposed(); } + + @Handler + private void handleMuteSound(TablexiaSettings.SoundMuteEvent event) { + if(event.isSoundMuted()) resetMusicButtonState(); + } } diff --git a/core/src/cz/nic/tablexia/screen/encyclopedia/content/model/Header.java b/core/src/cz/nic/tablexia/screen/encyclopedia/content/model/Header.java index 93a17523c18b0eed6c5ddf2ff96c0f0b3265f412..a254c0119c8dc2cebe39dbb3de6c5dea74235795 100644 --- a/core/src/cz/nic/tablexia/screen/encyclopedia/content/model/Header.java +++ b/core/src/cz/nic/tablexia/screen/encyclopedia/content/model/Header.java @@ -84,10 +84,11 @@ public class Header extends Content { } }; - if(TablexiaSettings.getInstance().isSoundMuted()) - showSoundMutedDialog(playButtonAction); - else + if(TablexiaSettings.getInstance().isSoundMuted() && button.isChecked()) { + showSoundMutedDialog(playButtonAction, button); + } else { playButtonAction.run(); + } } }); headerTable.add(headerLabel).maxWidth(parentContainerWidth - BUTTON_WIDTH - PAD_RIGHT).fillX().expandX().left(); @@ -98,7 +99,7 @@ public class Header extends Content { return headerTable; } - private void showSoundMutedDialog(final Runnable onSuccessCallback) { + private void showSoundMutedDialog(final Runnable onSuccessCallback, final ImageTablexiaButton button) { TablexiaComponentDialogFactory.getInstance().createWarningYesNoDialog( ApplicationTextManager.getInstance().getText(ApplicationTextManager.ApplicationTextsAssets.SOUND_MUTED_QUESTION), new ClickListener() { @@ -108,6 +109,12 @@ public class Header extends Content { onSuccessCallback.run(); } }, + new ClickListener(){ + @Override + public void clicked(InputEvent event, float x, float y) { + button.setUnchecked(); + } + }, true ).show(TablexiaComponentDialogFactory.WARNING_DIALOG_WIDTH, TablexiaComponentDialogFactory.WARNING_DIALOG_HEIGHT); } diff --git a/core/src/cz/nic/tablexia/screen/loader/IConnectionManager.java b/core/src/cz/nic/tablexia/screen/loader/IConnectionManager.java index 1c7365ea37695ff50c46c8c8ed0788b19a6acc46..0110773c46c8210f6ee0c2496a75697a10da0eaa 100644 --- a/core/src/cz/nic/tablexia/screen/loader/IConnectionManager.java +++ b/core/src/cz/nic/tablexia/screen/loader/IConnectionManager.java @@ -4,5 +4,12 @@ package cz.nic.tablexia.screen.loader; * Created by Drahomir Karchnak on 11/12/15. */ public interface IConnectionManager { + enum ConnectionType { + Wifi, + Mobile, + Ethernet, + Unknown; + } boolean isUsingMobileData(); + ConnectionType getConnectionType(); } diff --git a/core/src/cz/nic/tablexia/util/ui/TextFieldWithPlaceholder.java b/core/src/cz/nic/tablexia/util/ui/TextFieldWithPlaceholder.java index 93d8dbcfb9d74096a43c6509c42a6d2efbb47706..94f2ac1383698f86f6abc844cf2efa19cf5a5329 100644 --- a/core/src/cz/nic/tablexia/util/ui/TextFieldWithPlaceholder.java +++ b/core/src/cz/nic/tablexia/util/ui/TextFieldWithPlaceholder.java @@ -59,7 +59,7 @@ public class TextFieldWithPlaceholder extends TextField { } private static final Color DEFAULT_PLACEHOLDER_COLOR = Color.GRAY; - private static final int DEFAULT_PLACEHOLDER_ALIGN = Align.left; + private static final int DEFAULT_PLACEHOLDER_ALIGN = Align.center; private TablexiaTextFieldStyle tablexiaTextFieldStyle; private TablexiaLabel placeholder; diff --git a/core/src/cz/nic/tablexia/util/ui/dialog/components/TextFiledDialogComponent.java b/core/src/cz/nic/tablexia/util/ui/dialog/components/TextFiledDialogComponent.java index 3c178ea2f0ef4f0bdeea7354c02ba77b50948c0d..39b64976f3d8591687b56e3eb921294915239248 100644 --- a/core/src/cz/nic/tablexia/util/ui/dialog/components/TextFiledDialogComponent.java +++ b/core/src/cz/nic/tablexia/util/ui/dialog/components/TextFiledDialogComponent.java @@ -1,15 +1,20 @@ package cz.nic.tablexia.util.ui.dialog.components; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Cell; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.utils.Drawable; -import com.badlogic.gdx.scenes.scene2d.utils.FocusListener; import com.badlogic.gdx.utils.Align; +import java.util.Timer; +import java.util.TimerTask; + import cz.nic.tablexia.TablexiaSettings; import cz.nic.tablexia.loader.application.ApplicationAtlasManager; import cz.nic.tablexia.loader.application.ApplicationFontManager; @@ -25,8 +30,10 @@ public class TextFiledDialogComponent extends TablexiaDialogComponentAdapter { private static final ApplicationFontManager.FontType_NEW DEFAULT_FONT_TYPE = ApplicationFontManager.FontType_NEW.REGULAR_20; private static final int FONT_SIZE_RESIZE_THRESHOLD_STEP = 10; private static final String DEFAULT_PLACEHOLDER_TEXT = ""; - private static final int DEFAULT_TEXTFIELD_ALIGN = Align.left; + private static final int DEFAULT_TEXTFIELD_ALIGN = Align.center; private static final float DEFAULT_TEXT_FIELD_WIDTH_PERCENT = 1; + + public static final int DIALOG_REPLACE_TIMEOUT = 7000; private boolean isScaled; private final Color fontColor; @@ -39,7 +46,10 @@ public class TextFiledDialogComponent extends TablexiaDialogComponentAdapter { private TextFieldWithPlaceholder textField; private Cell content; - private FocusListener changePositionFocusListener; + private Timer timer; + private boolean timerSet; + + private InputListener repositionOnTypeListener, repositionOnTouchListener; public TextFiledDialogComponent() { this(null, DEFAULT_PLACEHOLDER_TEXT, DEFAULT_FONT_TYPE, DEFAULT_FONT_COLOR); @@ -59,7 +69,7 @@ public class TextFiledDialogComponent extends TablexiaDialogComponentAdapter { this.actualFontType = fontType; this.fontColor = fontColor; this.maximumLength = maximumLength; - + timerSet = false; textField = prepareTextField(placeholderText); } @@ -104,7 +114,6 @@ public class TextFiledDialogComponent extends TablexiaDialogComponentAdapter { if (maximumLength != null) { fieldWithPlaceholder.setMaxLength(maximumLength); } - fieldWithPlaceholder.setAlignment(DEFAULT_TEXTFIELD_ALIGN); return fieldWithPlaceholder; } @@ -119,31 +128,98 @@ public class TextFiledDialogComponent extends TablexiaDialogComponentAdapter { public void setRepositionOnFocusOnMobileDevices(boolean repositionOnFocus) { if(repositionOnFocus && TablexiaSettings.getInstance().isRunningOnMobileDevice()) { - if(changePositionFocusListener == null) prepareChangePositionFocusListener(); - textField.addListener(changePositionFocusListener); + if (repositionOnTypeListener == null) prepareOnTypeListener(); + if (repositionOnTouchListener == null) prepareOnTouchListener(); + textField.addListener(repositionOnTypeListener); + textField.addListener(repositionOnTouchListener); } else { - if(changePositionFocusListener != null) textField.removeListener(changePositionFocusListener); + if (repositionOnTypeListener != null) textField.removeListener(repositionOnTypeListener); + if (repositionOnTouchListener != null) textField.removeListener(repositionOnTouchListener); } } - private void prepareChangePositionFocusListener() { - this.changePositionFocusListener = new FocusListener() { + private void prepareOnTypeListener() { + this.repositionOnTypeListener = new InputListener() { + private static final int COMMON_INT_CODE_FOR_ENTER = 13; + private static final int ANDROID_INT_CODE_FOR_ENTER = 10; + @Override - public void keyboardFocusChanged(FocusListener.FocusEvent event, Actor actor, boolean focused) { - if(focused) repositionDialog(); + public boolean keyTyped(InputEvent event, char character) { + if (timerSet) timer.cancel(); + // have to check also (int)character because of some bug in iOS keyboard. It returns code Input.Keys.ENTER for every key after "done" button pressed + if ((event.getKeyCode() != Input.Keys.ENTER || ((int) character != ANDROID_INT_CODE_FOR_ENTER || (int) character != COMMON_INT_CODE_FOR_ENTER))) { + resetTimer(); + } else { + repositionDialog(DialogPosition.CENTER); + } + return false; } }; } + + + public void prepareOnTouchListener(){ + this.repositionOnTouchListener = new InputListener(){ + + @Override + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { + if (timerSet) timer.cancel(); + repositionDialog(DialogPosition.TOP); + resetTimer(); + return super.touchDown(event, x, y, pointer, button); + } + }; + } + + private void resetTimer() { + timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + repositionDialog(DialogPosition.CENTER); + timerSet = false; + } + }, DIALOG_REPLACE_TIMEOUT); + timerSet = true; + } - private void repositionDialog() { + private void repositionDialog(final DialogPosition dialogPosition) { TablexiaComponentDialog dialog = getDialog(); Stage stage = getStage(); if(dialog == null || (stage == null)) return; dialog.setPosition( - TablexiaSettings.getViewportLeftX(stage) + TablexiaSettings.getViewportWidth(stage) / 2f - dialog.getInnerWidth()/2f, - TablexiaSettings.getViewportBottomY(stage) + TablexiaSettings.getViewportHeight(stage) - dialog.getOutterHeight() + TablexiaSettings.getViewportLeftX(stage) + TablexiaSettings.getViewportWidth(stage) * 0.5f - dialog.getInnerWidth() * 0.5f, + TablexiaSettings.getViewportBottomY(stage) + TablexiaSettings.getViewportHeight(stage) * dialogPosition.getShift() - dialog.getOutterHeight() * dialogPosition.getShift() ); + + Gdx.app.postRunnable(new Runnable() { + @Override + public void run() { + Gdx.input.setOnscreenKeyboardVisible(dialogPosition.isShowKeyboard()); + } + }); + } + + private enum DialogPosition { + TOP(1f, true), + CENTER(0.5f, false); + + private float shift; + private boolean showKeyboard; + + DialogPosition(float shift, boolean showKeyboard) { + this.shift = shift; + this.showKeyboard = showKeyboard; + } + + public float getShift() { + return shift; + } + + public boolean isShowKeyboard() { + return showKeyboard; + } } } diff --git a/core/test/cz/nic/tablexia/test/games/AverageScoreTest.java b/core/test/cz/nic/tablexia/test/games/AverageScoreTest.java index 5d41641bdcda04b5b13d9aca4d9aee7dd6be08b8..065bc25b83e95da8a058843cfc4511f836eade16 100644 --- a/core/test/cz/nic/tablexia/test/games/AverageScoreTest.java +++ b/core/test/cz/nic/tablexia/test/games/AverageScoreTest.java @@ -3,21 +3,21 @@ package cz.nic.tablexia.test.games; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import cz.nic.tablexia.TablexiaSettings; import cz.nic.tablexia.game.GameDefinition; import cz.nic.tablexia.game.common.TablexiaRandom; import cz.nic.tablexia.game.difficulty.GameDifficulty; import cz.nic.tablexia.game.games.robbery.RobberyGame; +import cz.nic.tablexia.screen.statistics.StatisticsGameScoreResolver; +import cz.nic.tablexia.shared.model.Game; import cz.nic.tablexia.shared.model.GameScore; import cz.nic.tablexia.shared.model.User; -import cz.nic.tablexia.shared.model.Game; -import cz.nic.tablexia.screen.statistics.StatisticsGameScoreResolver; /** @@ -37,7 +37,21 @@ public class AverageScoreTest { List<GameScore> scores = new CopyOnWriteArrayList<GameScore>(); scores.add(new GameScore(key, (i * 10) + "")); TablexiaRandom random = new TablexiaRandom(); - Game game = new Game((long)i, user, GameDifficulty.EASY.getDifficultyNumber(), GameDefinition.ROBBERY.getGameNumber(), random.getSeed(), 0l, 1l); + Game game = new Game((long)i, + user, + GameDifficulty.EASY.getDifficultyNumber(), + GameDefinition.ROBBERY.getGameNumber(), + random.getSeed(), + 0l, + 1l, + TablexiaSettings.LocaleDefinition.cs_CZ.getLocaleNumber(), + "Tablexia AverageScoreTest", + 1, + "Tablexia AverageScoreTest", + 1, + TablexiaSettings.BuildType.DEBUG.getId(), + TablexiaSettings.Platform.DESKTOP.getId(), + "Serial"); game.setGameScoreMap(scores); games.add(game); } diff --git a/desktop/build.gradle b/desktop/build.gradle index d2ee4b621fd5fb7578f8a17ae9bf5428e4f34c4c..7c7be6b77659060c2fe2d8ec10d2deb57e940a73 100644 --- a/desktop/build.gradle +++ b/desktop/build.gradle @@ -27,6 +27,7 @@ task debugJar(type: Jar) { attributes 'Build-Type': 'debug' attributes 'Version-Name': tablexiaVersionName attributes 'Assets-Cheksums': getMapConvertedToString(rootProject.ext.assetsChecksum) + attributes 'Sentry-DSN': project.hasProperty('TABLEXIA_SENTRY_DSN_DEBUG') ? "$TABLEXIA_SENTRY_DSN_DEBUG" : "$project.sentryDSNFallbackValue"; } } } @@ -44,6 +45,7 @@ task releaseJar(type: Jar) { attributes 'Build-Type': 'release' attributes 'Version-Name': tablexiaVersionName attributes 'Assets-Cheksums': getMapConvertedToString(rootProject.ext.assetsChecksum) + attributes 'Sentry-DSN': project.hasProperty('TABLEXIA_SENTRY_DSN_RELEASE') ? "$TABLEXIA_SENTRY_DSN_RELEASE" : "$project.sentryDSNFallbackValue"; } } } diff --git a/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java b/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java index 2c10ac6529ab8738f0fd9d5abbeeced04223a356..8c73d1957876ef20ad3fb1c32eec556e3796e5e3 100644 --- a/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java +++ b/desktop/src/cz/nic/tablexia/desktop/DesktopLauncher.java @@ -14,8 +14,9 @@ import cz.nic.tablexia.screen.loader.IConnectionManager; public class DesktopLauncher { - private static final String BUILD_VARIANT_MANIFEST_ATTRIBUTE = "Build-Type"; - private static final boolean HAS_SOFT_BACK_BUTTON = true; + private static final String BUILD_VARIANT_MANIFEST_ATTRIBUTE = "Build-Type"; + private static final String SENTRY_DSN_KEY_MANIFEST_ATTRIBUTE = "Sentry-DSN"; + private static final boolean HAS_SOFT_BACK_BUTTON = true; private static final String DESKTOP_ICON_PATH = "icon/"; private static final String DESKTOP_ICON_16 = DESKTOP_ICON_PATH + "desktop_icon_16.png"; @@ -32,8 +33,8 @@ public class DesktopLauncher { public static final Tablexia.SQLConnectionType SQL_CONNECTION_TYPE = new Tablexia.SQLConnectionType("org.sqlite.JDBC", "jdbc:sqlite:"); public static void main(String[] arg) { - - String buildType = loadAttributeFromManifest(BUILD_VARIANT_MANIFEST_ATTRIBUTE, TablexiaSettings.BuildType.DEVEL.getKey()); + String buildType = loadAttributeFromManifest(BUILD_VARIANT_MANIFEST_ATTRIBUTE, TablexiaSettings.BuildType.DEVEL.getKey()); + String sentryDSN = loadAttributeFromManifest(SENTRY_DSN_KEY_MANIFEST_ATTRIBUTE, null); LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); config.resizable = buildType == null || buildType.equals(TablexiaSettings.BuildType.DEVEL.getKey()); @@ -56,7 +57,7 @@ public class DesktopLauncher { config.addIcon(DESKTOP_ICON_128, Files.FileType.Internal); } - new LwjglApplication(new Tablexia(buildType, Locale.getDefault(), SQL_CONNECTION_TYPE, new DesktopConnectionManager(), HAS_SOFT_BACK_BUTTON, true), config); + new LwjglApplication(new Tablexia(buildType, Locale.getDefault(), SQL_CONNECTION_TYPE, new DesktopConnectionManager(), sentryDSN, HAS_SOFT_BACK_BUTTON, true, null), config); } private static String loadAttributeFromManifest(String attributeName, String defaultValue) { @@ -69,8 +70,13 @@ public class DesktopLauncher { private static class DesktopConnectionManager implements IConnectionManager { @Override public boolean isUsingMobileData() { - //TODO - return false.. its desktop ;) - return false;//TablexiaSettings.getInstance().getBuildType() == TablexiaSettings.BuildType.DEVEL; + return false; //Just desktop things... } + + @Override + public ConnectionType getConnectionType() { + //TODO - Wifi || Ethernet in Java? + return ConnectionType.Ethernet; + } } } diff --git a/ios/Info.plist.xml b/ios/Info.plist.xml index 7ba837f46a6811006ed593ac647c5ff869c683b1..44c79338b44c36e922ffbf51acd3816f7e2da01d 100644 --- a/ios/Info.plist.xml +++ b/ios/Info.plist.xml @@ -24,6 +24,8 @@ <string>${app.build}</string> <key>cz.nic.tablexia.BuildType</key> <string>${app.buildtype}</string> + <key>cz.nic.tablexia.SentryDSN</key> + <string>${app.sentryDSN}</string> <key>LSRequiresIPhoneOS</key> <true/> <key>UIViewControllerBasedStatusBarAppearance</key> diff --git a/ios/build.gradle b/ios/build.gradle index cb42d8ee7273cc52ecec2dc223b7b0ccfc4ec0a2..7b94a0a1daa089c7fbe88fda96a0b98110703430 100644 --- a/ios/build.gradle +++ b/ios/build.gradle @@ -13,7 +13,7 @@ ext { } // Updates or create a robovm.properties file. -def updateRoboVMProperties(String buildType, String applicationId, String iconName) { +def updateRoboVMProperties(String buildType, String applicationId, String iconName, String DSN) { Properties props = new Properties() def propsFile = file('robovm.properties') @@ -30,6 +30,7 @@ def updateRoboVMProperties(String buildType, String applicationId, String iconNa props.setProperty('app.buildtype', buildType) props.setProperty('app.build', '' + tablexiaVersionCode) props.setProperty('app.executable', tablexiaAppName + '-' + buildType + '-' + tablexiaVersionName) + props.setProperty('app.sentryDSN', DSN) props.store(propsFile.newDataOutputStream(), '') } @@ -78,24 +79,25 @@ task updateRoboVMXML << { tasks.launchIPadSimulator.doFirst { robovm.iosSignIdentity = TABLEXIA_IOS_SIGNING_IDENTITY - updateRoboVMProperties("devel", applicationIdDevel, 'Icon_devel') + updateRoboVMProperties("devel", applicationIdDevel, 'Icon_devel', sentryDSNFallbackValue) } tasks.launchIPhoneSimulator.doFirst { robovm.iosSignIdentity = TABLEXIA_IOS_SIGNING_IDENTITY - updateRoboVMProperties("devel", applicationIdDevel, 'Icon_devel') + updateRoboVMProperties("devel", applicationIdDevel, 'Icon_devel', sentryDSNFallbackValue) } tasks.launchIOSDevice.doFirst { robovm.iosSignIdentity = TABLEXIA_IOS_SIGNING_IDENTITY - updateRoboVMProperties("devel", applicationIdDevel, 'Icon_devel') + updateRoboVMProperties("devel", applicationIdDevel, 'Icon_devel', sentryDSNFallbackValue) } tasks.create(name: "createDebugIPA", type: org.robovm.gradle.tasks.ArchiveTask) { doFirst { robovm.iosSignIdentity = TABLEXIA_IOS_SIGNING_IDENTITY robovm.iosProvisioningProfile = TABLEXIA_IOS_DEBUG_PROVISIONING - updateRoboVMProperties("debug", applicationIdDebug, 'Icon_debug') + String DSN = project.hasProperty('TABLEXIA_SENTRY_DSN_DEBUG') ? "$TABLEXIA_SENTRY_DSN_DEBUG" : sentryDSNFallbackValue; + updateRoboVMProperties("debug", applicationIdDebug, 'Icon_debug', DSN) } } @@ -103,7 +105,8 @@ tasks.create(name: "createReleaseIPA", type: org.robovm.gradle.tasks.ArchiveTask doFirst { robovm.iosSignIdentity = TABLEXIA_IOS_SIGNING_IDENTITY robovm.iosProvisioningProfile = TABLEXIA_IOS_RELEASE_PROVISIONING - updateRoboVMProperties("release", applicationIdRelease, 'Icon_release') + String DSN = project.hasProperty('TABLEXIA_SENTRY_DSN_RELEASE') ? "$TABLEXIA_SENTRY_DSN_RELEASE" : sentryDSNFallbackValue; + updateRoboVMProperties("release", applicationIdRelease, 'Icon_release', DSN) } } diff --git a/ios/robovm.xml b/ios/robovm.xml index b0564fb819c5c1e53ba379280ff9154e3bd08de8..67fc3bd2a5ef75e58482723dc5e514623ba0a0b8 100644 --- a/ios/robovm.xml +++ b/ios/robovm.xml @@ -19,7 +19,6 @@ </resources> <forceLinkClasses> <pattern>com.badlogic.gdx.scenes.scene2d.ui.*</pattern> - <pattern>com.badlogic.gdx.physics.bullet.**</pattern> <pattern>com.android.okhttp.HttpHandler</pattern> <pattern>com.android.okhttp.HttpsHandler</pattern> <pattern>com.android.org.conscrypt.**</pattern> @@ -31,9 +30,11 @@ <pattern>com.android.org.bouncycastle.crypto.digests.AndroidDigestFactoryOpenSSL</pattern> <pattern>org.apache.harmony.security.provider.cert.DRLCertFactory</pattern> <pattern>org.apache.harmony.security.provider.crypto.CryptoProvider</pattern> + <pattern>java.util.logging.ConsoleHandler</pattern> + <pattern>java.util.logging.SimpleFormatter</pattern> <pattern>SQLite.**</pattern> </forceLinkClasses> - <libs/> + <libs></libs> <frameworks> <framework>UIKit</framework> <framework>OpenGLES</framework> diff --git a/ios/src/cz/nic/tablexia/IOSLauncher.java b/ios/src/cz/nic/tablexia/IOSLauncher.java index 276730aca4e2246284e10d34beb406d967ac0114..3e945131700e0d9edf2cb22f66460742a03380f5 100644 --- a/ios/src/cz/nic/tablexia/IOSLauncher.java +++ b/ios/src/cz/nic/tablexia/IOSLauncher.java @@ -5,6 +5,8 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.backends.iosrobovm.IOSApplication; import com.badlogic.gdx.backends.iosrobovm.IOSApplicationConfiguration; +import org.robovm.apple.foundation.NSException; +import org.robovm.objc.block.VoidBlock1; import org.robovm.apple.foundation.NSAutoreleasePool; import org.robovm.apple.foundation.NSBundle; import org.robovm.apple.foundation.NSDictionary; @@ -22,16 +24,19 @@ import cz.nic.tablexia.screen.loader.IConnectionManager; public class IOSLauncher extends IOSApplication.Delegate { - public static final Tablexia.SQLConnectionType SQL_CONNECTION_TYPE = new Tablexia.SQLConnectionType("SQLite.JDBCDriver", "jdbc:sqlite:"); - private static final boolean HAS_SOFT_BACK_BUTTON = true; + private static final String TABLEXIA_BUILD_TYPE_KEY = "cz.nic.tablexia.BuildType"; + private static final String TABLEXIA_SENTRY_DSN_KEY = "cz.nic.tablexia.SentryDSN"; - private static final String FALLBACK_CONNECTION_CHECK_HOST = "nic.cz"; - private static final Integer FALLBACK_CONNECTION_CHECK_PORT = 80; + public static final Tablexia.SQLConnectionType SQL_CONNECTION_TYPE = new Tablexia.SQLConnectionType("SQLite.JDBCDriver", "jdbc:sqlite:"); + private static final boolean HAS_SOFT_BACK_BUTTON = true; - private static final String CONNECTION_CHECK_HOST = TablexiaBuildConfig.TABLEXIA_SERVER_HOST != null ? TablexiaBuildConfig.TABLEXIA_SERVER_HOST : FALLBACK_CONNECTION_CHECK_HOST; - private static final Integer CONNECTION_CHECK_PORT = TablexiaBuildConfig.TABLEXIA_SERVER_PORT != null ? TablexiaBuildConfig.TABLEXIA_SERVER_PORT : FALLBACK_CONNECTION_CHECK_PORT; + private static final String FALLBACK_CONNECTION_CHECK_HOST = "nic.cz"; + private static final Integer FALLBACK_CONNECTION_CHECK_PORT = 80; - private TablexiaIOSFiles tablexiaIOSFiles; + private static final String CONNECTION_CHECK_HOST = TablexiaBuildConfig.TABLEXIA_SERVER_HOST != null ? TablexiaBuildConfig.TABLEXIA_SERVER_HOST : FALLBACK_CONNECTION_CHECK_HOST; + private static final Integer CONNECTION_CHECK_PORT = TablexiaBuildConfig.TABLEXIA_SERVER_PORT != null ? TablexiaBuildConfig.TABLEXIA_SERVER_PORT : FALLBACK_CONNECTION_CHECK_PORT; + + private TablexiaIOSFiles tablexiaIOSFiles; @Override protected IOSApplication createApplication() { @@ -39,15 +44,18 @@ public class IOSLauncher extends IOSApplication.Delegate { config.multisample = GLKViewDrawableMultisample._4X; NSDictionary infoDictionary = NSBundle.getMainBundle().getInfoDictionary(); - String buildType = infoDictionary.get(new NSString("cz.nic.tablexia.BuildType")).toString(); - + String buildType = infoDictionary.get(new NSString(TABLEXIA_BUILD_TYPE_KEY)).toString(); + String sentryDSN = infoDictionary.get(new NSString(TABLEXIA_SENTRY_DSN_KEY)).toString(); + tablexiaIOSFiles = new TablexiaIOSFiles(); IOSApplication iosApplication = new IOSApplication(new Tablexia(buildType, Locale.getDefault(), SQL_CONNECTION_TYPE, new IOSConnectionManager(), + sentryDSN, HAS_SOFT_BACK_BUTTON, - false), config) { + false, + null), config) { @Override public Files getFiles() { @@ -61,10 +69,29 @@ public class IOSLauncher extends IOSApplication.Delegate { @Override public boolean didFinishLaunching(UIApplication application, UIApplicationLaunchOptions launchOptions) { boolean result = super.didFinishLaunching(application, launchOptions); + + registerUncaughtExceptionHandler(); + Gdx.files = tablexiaIOSFiles; return result; } + private void registerUncaughtExceptionHandler() { + NSException.setUncaughtExceptionHandler(new VoidBlock1<NSException>() { + @Override + public void invoke(final NSException e) { + String exceptionMsg = e.getName() + ": " + e.getReason(); + + StackTraceElement[] elements = new StackTraceElement[e.getCallStackSymbols().size()]; + for(int i = 0; i < elements.length; i++) { + elements[i] = new StackTraceElement(e.getCallStackSymbols().get(i).toString(), "", "", 0); + } + + TablexiaRaven.sendCustomException(TablexiaRaven.ExceptionType.IOSException, exceptionMsg, elements); + } + }); + } + public static void main(String[] argv) { NSAutoreleasePool pool = new NSAutoreleasePool(); UIApplication.main(argv, null, IOSLauncher.class); @@ -74,14 +101,21 @@ public class IOSLauncher extends IOSApplication.Delegate { private static class IOSConnectionManager implements IConnectionManager { @Override public boolean isUsingMobileData() { + return getConnectionType() == ConnectionType.Mobile; + } + + @Override + public ConnectionType getConnectionType() { InetSocketAddress socketAddress = new InetSocketAddress(CONNECTION_CHECK_HOST, CONNECTION_CHECK_PORT); // RoboVM tries to retrive IP address using network connection. If we don't have it InetSocketAddress.getAddress() returns null // in that case SCNetworkReachability.create(socketAddress) throws IllegalArgumentException if (socketAddress.getAddress() == null) { - return false; + return ConnectionType.Unknown; } SCNetworkReachabilityFlags flags = SCNetworkReachability.create(socketAddress).getFlags(); - return flags.compareTo(SCNetworkReachabilityFlags.IsWWAN) == 1; + + if(flags.compareTo(SCNetworkReachabilityFlags.IsWWAN) == 1) return ConnectionType.Mobile; + else return ConnectionType.Wifi; } } -} \ No newline at end of file +}