Get the consumer friendly name of an Android device.
- * - *On many popular devices the market name of the device is not available. For example, on the - * Samsung Galaxy S6 the value of {@link Build#MODEL} could be "SM-G920F", "SM-G920I", "SM-G920W8", - * etc.
- * - *See the usages below to get the consumer friends name of a device:
- * - *Get the name of the current device:
- * - *- * String deviceName = DeviceName.getDeviceName(); - *- * - *
The above code will get the correct device name for the top 600 Android devices. If the - * device is unrecognized, then Build.MODEL is returned.
- * - *Get the name of a device using the device's codename:
- * - *
- * // Retruns "Moto X Style"
- * DeviceName.getDeviceName("clark", "Unknown device");
- *
- *
- * Get information about the device:
- * - *
- * DeviceName.with(context).request(new DeviceName.Callback() {
- *
- * @Override public void onFinished(DeviceName.DeviceInfo info, Exception error) {
- * String manufacturer = info.manufacturer; // "Samsung"
- * String name = info.marketName; // "Galaxy S6 Edge"
- * String model = info.model; // "SM-G925I"
- * String codename = info.codename; // "zerolte"
- * String deviceName = info.getName(); // "Galaxy S6 Edge"
- * // FYI: We are on the UI thread.
- * }
- * });
- *
- *
- * The above code loads JSON from a generated list of device names based on Google's maintained - * list. It will be up-to-date with Google's supported device list so that you will get the correct - * name for new or unknown devices. This supports over 10,000 devices.
- * - *This will only make a network call once. The value is saved to SharedPreferences for future - * calls.
- */ -public class DeviceName { - // @formatter:on - - // JSON which is derived from Google's PDF document which contains all devices on Google Play. - // To get the URL to the JSON file which contains information about the device name: - // String url = String.format(DEVICE_JSON_URL, Build.DEVICE); - private static final String DEVICE_JSON_URL = - "https://raw.githubusercontent.com/jaredrummler/AndroidDeviceNames/master/json/devices/%s.json"; - - // Preference filename for storing device info so we don't need to download it again. - private static final String SHARED_PREF_NAME = "device_names"; - - /** - * Create a new request to get information about a device. - * - * @param context the application context - * @return a new Request instance. - */ - public static Request with(Context context) { - return new Request(context.getApplicationContext()); - } - - /** - * Get the consumer friendly name of the device. - * - * @return the market name of the current device. - * @see #getDeviceName(String, String) - */ - public static String getDeviceName() { - return getDeviceName(Build.DEVICE, Build.MODEL, capitalize(Build.MODEL)); - } - - /** - * Get the consumer friendly name of a device. - * - * @param codename the value of the system property "ro.product.device" ({@link Build#DEVICE}) - * or - * the value of the system property "ro.product.model" ({@link Build#MODEL}) - * @param fallback the fallback name if the device is unknown. Usually the value of the system property - * "ro.product.model" ({@link Build#MODEL}) - * @return the market name of a device or {@code fallback} if the device is unknown. - */ - public static String getDeviceName(String codename, String fallback) { - return getDeviceName(codename, codename, fallback); - } - - /** - * Get the consumer friendly name of a device. - * - * @param codename the value of the system property "ro.product.device" ({@link Build#DEVICE}). - * @param model the value of the system property "ro.product.model" ({@link Build#MODEL}). - * @param fallback the fallback name if the device is unknown. Usually the value of the system property - * "ro.product.model" ({@link Build#MODEL}) - * @return the market name of a device or {@code fallback} if the device is unknown. - */ - public static String getDeviceName(String codename, String model, String fallback) { - // ---------------------------------------------------------------------------- - // Google - if ((codename != null && codename.equals("walleye"))) { - return "Pixel 2"; - } - if ((codename != null && codename.equals("taimen"))) { - return "Pixel 2 XL"; - } - if ((codename != null && codename.equals("blueline"))) { - return "Pixel 3"; - } - if ((codename != null && codename.equals("crosshatch"))) { - return "Pixel 3 XL"; - } - if ((codename != null && codename.equals("sargo"))) { - return "Pixel 3a"; - } - if ((codename != null && codename.equals("bonito"))) { - return "Pixel 3a XL"; - } - // ---------------------------------------------------------------------------- - // Huawei - if ((codename != null && (codename.equals("HWBND-H"))) || (model != null && (model.equals("BND-L21") - || model.equals("BND-L24") - || model.equals("BND-L31")))) { - return "Honor 7X"; - } - if ((codename != null && (codename.equals("HWBKL"))) || (model != null && (model.equals("BKL-L04") || model.equals( - "BKL-L09")))) { - return "Honor View 10"; - } - if ((codename != null && (codename.equals("HWALP"))) || (model != null && (model.equals("ALP-AL00") || model.equals( - "ALP-L09") || model.equals("ALP-L29") || model.equals("ALP-TL00")))) { - return "Mate 10"; - } - if ((codename != null && (codename.equals("HWMHA"))) || (model != null && (model.equals("MHA-AL00") || model.equals( - "MHA-L09") || model.equals("MHA-L29") || model.equals("MHA-TL00")))) { - return "Mate 9"; - } - if ((codename != null && codename.equals("angler"))) { - return "Nexus 6P"; - } - // ---------------------------------------------------------------------------- - // LGE - if ((codename != null && (codename.equals("h1"))) || (model != null && (model.equals("LG-F700K") || model.equals( - "LG-F700L") || model.equals("LG-F700S") || model.equals("LG-H820") || model.equals("LG-H820PR") || model.equals( - "LG-H830") || model.equals("LG-H831") || model.equals("LG-H850") || model.equals("LG-H858") || model.equals( - "LG-H860") || model.equals("LG-H868") || model.equals("LGAS992") || model.equals("LGLS992") || model.equals( - "LGUS992") || model.equals("RS988") || model.equals("VS987")))) { - return "LG G5"; - } - if ((codename != null && (codename.equals("lucye"))) || (model != null && (model.equals("LG-AS993") - || model.equals("LG-H870") - || model.equals("LG-H870AR") - || model.equals("LG-H870DS") - || model.equals("LG-H870I") - || model.equals("LG-H870S") - || model.equals("LG-H871") - || model.equals("LG-H871S") - || model.equals("LG-H872") - || model.equals("LG-H872PR") - || model.equals("LG-H873") - || model.equals("LG-LS993") - || model.equals("LGM-G600K") - || model.equals("LGM-G600L") - || model.equals("LGM-G600S") - || model.equals("LGUS997") - || model.equals("VS988")))) { - return "LG G6"; - } - if ((codename != null && (codename.equals("flashlmdd"))) || (model != null && (model.equals("LM-V500") - || model.equals("LM-V500N")))) { - return "LG V50 ThinQ"; - } - if ((codename != null && codename.equals("mako"))) { - return "Nexus 4"; - } - if ((codename != null && codename.equals("hammerhead"))) { - return "Nexus 5"; - } - if ((codename != null && codename.equals("bullhead"))) { - return "Nexus 5X"; - } - // ---------------------------------------------------------------------------- - // Motorola - if ((codename != null && (codename.equals("griffin"))) || (model != null && (model.equals("XT1650") || model.equals( - "XT1650-05")))) { - return "Moto Z"; - } - if ((codename != null && codename.equals("shamu"))) { - return "Nexus 6"; - } - // ---------------------------------------------------------------------------- - // Nokia - if ((codename != null && (codename.equals("RHD") - || codename.equals("ROO") - || codename.equals("ROON_sprout") - || codename.equals("ROO_sprout")))) { - return "Nokia 3.1 Plus"; - } - if ((codename != null && codename.equals("CTL_sprout"))) { - return "Nokia 7.1"; - } - // ---------------------------------------------------------------------------- - // OnePlus - if ((codename != null && codename.equals("OnePlus6")) || (model != null && model.equals("ONEPLUS A6003"))) { - return "OnePlus 6"; - } - if ((codename != null && (codename.equals("OnePlus6T") || codename.equals("OnePlus6TSingle"))) || (model != null - && (model.equals("ONEPLUS A6013")))) { - return "OnePlus 6T"; - } - if ((codename != null && codename.equals("OnePlus7")) || (model != null && model.equals("GM1905"))) { - return "OnePlus 7"; - } - if ((codename != null && (codename.equals("OnePlus7Pro") || codename.equals("OnePlus7ProTMO"))) || (model != null - && (model.equals("GM1915") || model.equals("GM1917")))) { - return "OnePlus 7 Pro"; - } - // ---------------------------------------------------------------------------- - // Samsung - if ((codename != null && (codename.equals("a50"))) || (model != null && (model.equals("SM-A505F") - || model.equals("SM-A505FM") - || model.equals("SM-A505FN") - || model.equals("SM-A505G") - || model.equals("SM-A505GN") - || model.equals("SM-A505GT") - || model.equals("SM-A505N") - || model.equals("SM-A505U") - || model.equals("SM-A505W") - || model.equals("SM-A505YN")))) { - return "Galaxy A50"; - } - if ((codename != null && (codename.equals("a6elteaio") - || codename.equals("a6elteatt") - || codename.equals("a6eltemtr") - || codename.equals("a6eltespr") - || codename.equals("a6eltetmo") - || codename.equals("a6elteue") - || codename.equals("a6lte") - || codename.equals("a6lteks"))) || (model != null && (model.equals("SM-A600A") - || model.equals("SM-A600AZ") - || model.equals("SM-A600F") - || model.equals("SM-A600FN") - || model.equals("SM-A600G") - || model.equals("SM-A600GN") - || model.equals("SM-A600N") - || model.equals("SM-A600P") - || model.equals("SM-A600T") - || model.equals("SM-A600T1") - || model.equals("SM-A600U")))) { - return "Galaxy A6"; - } - if ((codename != null && (codename.equals("SC-01J") - || codename.equals("SCV34") - || codename.equals("gracelte") - || codename.equals("graceltektt") - || codename.equals("graceltelgt") - || codename.equals("gracelteskt") - || codename.equals("graceqlteacg") - || codename.equals("graceqlteatt") - || codename.equals("graceqltebmc") - || codename.equals("graceqltechn") - || codename.equals("graceqltedcm") - || codename.equals("graceqltelra") - || codename.equals("graceqltespr") - || codename.equals("graceqltetfnvzw") - || codename.equals("graceqltetmo") - || codename.equals("graceqlteue") - || codename.equals("graceqlteusc") - || codename.equals("graceqltevzw"))) || (model != null && (model.equals("SAMSUNG-SM-N930A") - || model.equals("SC-01J") - || model.equals("SCV34") - || model.equals("SGH-N037") - || model.equals("SM-N9300") - || model.equals("SM-N930F") - || model.equals("SM-N930K") - || model.equals("SM-N930L") - || model.equals("SM-N930P") - || model.equals("SM-N930R4") - || model.equals("SM-N930R6") - || model.equals("SM-N930R7") - || model.equals("SM-N930S") - || model.equals("SM-N930T") - || model.equals("SM-N930U") - || model.equals("SM-N930V") - || model.equals("SM-N930VL") - || model.equals("SM-N930W8") - || model.equals("SM-N930X")))) { - return "Galaxy Note7"; - } - if ((codename != null && (codename.equals("SC-01K") - || codename.equals("SCV37") - || codename.equals("greatlte") - || codename.equals("greatlteks") - || codename.equals("greatqlte") - || codename.equals("greatqltechn") - || codename.equals("greatqltecmcc") - || codename.equals("greatqltecs") - || codename.equals("greatqlteue"))) || (model != null && (model.equals("SC-01K") - || model.equals("SCV37") - || model.equals("SM-N9500") - || model.equals("SM-N9508") - || model.equals("SM-N950F") - || model.equals("SM-N950N") - || model.equals("SM-N950U") - || model.equals("SM-N950U1") - || model.equals("SM-N950W") - || model.equals("SM-N950XN")))) { - return "Galaxy Note8"; - } - if ((codename != null && (codename.equals("SC-01L") - || codename.equals("SCV40") - || codename.equals("crownlte") - || codename.equals("crownlteks") - || codename.equals("crownqltechn") - || codename.equals("crownqltecs") - || codename.equals("crownqltesq") - || codename.equals("crownqlteue"))) || (model != null && (model.equals("SC-01L") - || model.equals("SCV40") - || model.equals("SM-N9600") - || model.equals("SM-N960F") - || model.equals("SM-N960N") - || model.equals("SM-N960U") - || model.equals("SM-N960U1") - || model.equals("SM-N960W")))) { - return "Galaxy Note9"; - } - if ((codename != null && (codename.equals("SC-03L") - || codename.equals("SCV41") - || codename.equals("beyond1") - || codename.equals("beyond1q"))) || (model != null && (model.equals("SC-03L") - || model.equals("SCV41") - || model.equals("SM-G9730") - || model.equals("SM-G9738") - || model.equals("SM-G973F") - || model.equals("SM-G973N") - || model.equals("SM-G973U") - || model.equals("SM-G973U1") - || model.equals("SM-G973W")))) { - return "Galaxy S10"; - } - if ((codename != null && (codename.equals("SC-04L") - || codename.equals("SCV42") - || codename.equals("beyond2") - || codename.equals("beyond2q"))) || (model != null && (model.equals("SC-04L") - || model.equals("SCV42") - || model.equals("SM-G9750") - || model.equals("SM-G9758") - || model.equals("SM-G975F") - || model.equals("SM-G975N") - || model.equals("SM-G975U") - || model.equals("SM-G975U1") - || model.equals("SM-G975W")))) { - return "Galaxy S10+"; - } - if ((codename != null && (codename.equals("beyond0") || codename.equals("beyond0q"))) || (model != null - && (model.equals("SM-G9700") - || model.equals("SM-G9708") - || model.equals("SM-G970F") - || model.equals("SM-G970N") - || model.equals("SM-G970U") - || model.equals("SM-G970U1") - || model.equals("SM-G970W")))) { - return "Galaxy S10e"; - } - if ((codename != null && (codename.equals("SC-04F") - || codename.equals("SCL23") - || codename.equals("k3g") - || codename.equals("klte") - || codename.equals("klteMetroPCS") - || codename.equals("klteacg") - || codename.equals("klteaio") - || codename.equals("klteatt") - || codename.equals("kltecan") - || codename.equals("klteduoszn") - || codename.equals("kltektt") - || codename.equals("kltelgt") - || codename.equals("kltelra") - || codename.equals("klteskt") - || codename.equals("kltespr") - || codename.equals("kltetfnvzw") - || codename.equals("kltetmo") - || codename.equals("klteusc") - || codename.equals("kltevzw") - || codename.equals("kwifi") - || codename.equals("lentisltektt") - || codename.equals("lentisltelgt") - || codename.equals("lentislteskt"))) || (model != null && (model.equals("SAMSUNG-SM-G900A") - || model.equals("SAMSUNG-SM-G900AZ") - || model.equals("SC-04F") - || model.equals("SCL23") - || model.equals("SM-G9006W") - || model.equals("SM-G9008W") - || model.equals("SM-G9009W") - || model.equals("SM-G900F") - || model.equals("SM-G900FQ") - || model.equals("SM-G900H") - || model.equals("SM-G900I") - || model.equals("SM-G900K") - || model.equals("SM-G900L") - || model.equals("SM-G900M") - || model.equals("SM-G900MD") - || model.equals("SM-G900P") - || model.equals("SM-G900R4") - || model.equals("SM-G900R6") - || model.equals("SM-G900R7") - || model.equals("SM-G900S") - || model.equals("SM-G900T") - || model.equals("SM-G900T1") - || model.equals("SM-G900T3") - || model.equals("SM-G900T4") - || model.equals("SM-G900V") - || model.equals("SM-G900W8") - || model.equals("SM-G900X") - || model.equals("SM-G906K") - || model.equals("SM-G906L") - || model.equals("SM-G906S") - || model.equals("SM-S903VL")))) { - return "Galaxy S5"; - } - if ((codename != null && (codename.equals("s5neolte") || codename.equals("s5neoltecan"))) || (model != null && ( - model.equals("SM-G903F") - || model.equals("SM-G903M") - || model.equals("SM-G903W")))) { - return "Galaxy S5 Neo"; - } - if ((codename != null && (codename.equals("SC-05G") - || codename.equals("zeroflte") - || codename.equals("zeroflteacg") - || codename.equals("zeroflteaio") - || codename.equals("zeroflteatt") - || codename.equals("zerofltebmc") - || codename.equals("zerofltechn") - || codename.equals("zerofltectc") - || codename.equals("zerofltektt") - || codename.equals("zerofltelgt") - || codename.equals("zerofltelra") - || codename.equals("zerofltemtr") - || codename.equals("zeroflteskt") - || codename.equals("zerofltespr") - || codename.equals("zerofltetfnvzw") - || codename.equals("zerofltetmo") - || codename.equals("zeroflteusc") - || codename.equals("zerofltevzw"))) || (model != null && (model.equals("SAMSUNG-SM-G920A") - || model.equals("SAMSUNG-SM-G920AZ") - || model.equals("SC-05G") - || model.equals("SM-G9200") - || model.equals("SM-G9208") - || model.equals("SM-G9209") - || model.equals("SM-G920F") - || model.equals("SM-G920I") - || model.equals("SM-G920K") - || model.equals("SM-G920L") - || model.equals("SM-G920P") - || model.equals("SM-G920R4") - || model.equals("SM-G920R6") - || model.equals("SM-G920R7") - || model.equals("SM-G920S") - || model.equals("SM-G920T") - || model.equals("SM-G920T1") - || model.equals("SM-G920V") - || model.equals("SM-G920W8") - || model.equals("SM-G920X") - || model.equals("SM-S906L") - || model.equals("SM-S907VL")))) { - return "Galaxy S6"; - } - if ((codename != null && (codename.equals("404SC") - || codename.equals("SC-04G") - || codename.equals("SCV31") - || codename.equals("zerolte") - || codename.equals("zerolteacg") - || codename.equals("zerolteatt") - || codename.equals("zeroltebmc") - || codename.equals("zeroltechn") - || codename.equals("zeroltektt") - || codename.equals("zeroltelra") - || codename.equals("zerolteskt") - || codename.equals("zeroltespr") - || codename.equals("zeroltetmo") - || codename.equals("zerolteusc") - || codename.equals("zeroltevzw"))) || (model != null && (model.equals("404SC") - || model.equals("SAMSUNG-SM-G925A") - || model.equals("SC-04G") - || model.equals("SCV31") - || model.equals("SM-G9250") - || model.equals("SM-G925I") - || model.equals("SM-G925K") - || model.equals("SM-G925P") - || model.equals("SM-G925R4") - || model.equals("SM-G925R6") - || model.equals("SM-G925R7") - || model.equals("SM-G925S") - || model.equals("SM-G925T") - || model.equals("SM-G925V") - || model.equals("SM-G925W8") - || model.equals("SM-G925X")))) { - return "Galaxy S6 Edge"; - } - if ((codename != null && (codename.equals("zenlte") - || codename.equals("zenlteatt") - || codename.equals("zenltebmc") - || codename.equals("zenltechn") - || codename.equals("zenltektt") - || codename.equals("zenltekx") - || codename.equals("zenltelgt") - || codename.equals("zenlteskt") - || codename.equals("zenltespr") - || codename.equals("zenltetmo") - || codename.equals("zenlteusc") - || codename.equals("zenltevzw"))) || (model != null && (model.equals("SAMSUNG-SM-G928A") - || model.equals("SM-G9280") - || model.equals("SM-G9287C") - || model.equals("SM-G928C") - || model.equals("SM-G928G") - || model.equals("SM-G928I") - || model.equals("SM-G928K") - || model.equals("SM-G928L") - || model.equals("SM-G928N0") - || model.equals("SM-G928P") - || model.equals("SM-G928R4") - || model.equals("SM-G928S") - || model.equals("SM-G928T") - || model.equals("SM-G928V") - || model.equals("SM-G928W8") - || model.equals("SM-G928X")))) { - return "Galaxy S6 Edge+"; - } - if ((codename != null && (codename.equals("herolte") || codename.equals("heroltebmc") || codename.equals( - "heroltektt") || codename.equals("heroltelgt") || codename.equals("herolteskt") || codename.equals( - "heroqlteacg") || codename.equals("heroqlteaio") || codename.equals("heroqlteatt") || codename.equals( - "heroqltecctvzw") || codename.equals("heroqltechn") || codename.equals("heroqltelra") || codename.equals( - "heroqltemtr") || codename.equals("heroqltespr") || codename.equals("heroqltetfnvzw") || codename.equals( - "heroqltetmo") || codename.equals("heroqlteue") || codename.equals("heroqlteusc") || codename.equals( - "heroqltevzw"))) || (model != null && (model.equals("SAMSUNG-SM-G930A") - || model.equals("SAMSUNG-SM-G930AZ") - || model.equals("SM-G9300") - || model.equals("SM-G9308") - || model.equals("SM-G930F") - || model.equals("SM-G930K") - || model.equals("SM-G930L") - || model.equals("SM-G930P") - || model.equals("SM-G930R4") - || model.equals("SM-G930R6") - || model.equals("SM-G930R7") - || model.equals("SM-G930S") - || model.equals("SM-G930T") - || model.equals("SM-G930T1") - || model.equals("SM-G930U") - || model.equals("SM-G930V") - || model.equals("SM-G930VC") - || model.equals("SM-G930VL") - || model.equals("SM-G930W8") - || model.equals("SM-G930X")))) { - return "Galaxy S7"; - } - if ((codename != null && (codename.equals("SC-02H") - || codename.equals("SCV33") - || codename.equals("hero2lte") - || codename.equals("hero2ltebmc") - || codename.equals("hero2ltektt") - || codename.equals("hero2lteskt") - || codename.equals("hero2qlteatt") - || codename.equals("hero2qltecctvzw") - || codename.equals("hero2qltespr") - || codename.equals("hero2qltetmo") - || codename.equals("hero2qlteusc") - || codename.equals("hero2qltevzw"))) || (model != null && (model.equals("SAMSUNG-SM-G935A") - || model.equals("SC-02H") - || model.equals("SCV33") - || model.equals("SM-G935K") - || model.equals("SM-G935P") - || model.equals("SM-G935R4") - || model.equals("SM-G935S") - || model.equals("SM-G935T") - || model.equals("SM-G935V") - || model.equals("SM-G935VC") - || model.equals("SM-G935W8") - || model.equals("SM-G935X")))) { - return "Galaxy S7 Edge"; - } - if ((codename != null && (codename.equals("SC-02J") - || codename.equals("SCV36") - || codename.equals("dreamlte") - || codename.equals("dreamlteks") - || codename.equals("dreamqltecan") - || codename.equals("dreamqltechn") - || codename.equals("dreamqltecmcc") - || codename.equals("dreamqltesq") - || codename.equals("dreamqlteue"))) || (model != null && (model.equals("SC-02J") - || model.equals("SCV36") - || model.equals("SM-G9500") - || model.equals("SM-G9508") - || model.equals("SM-G950F") - || model.equals("SM-G950N") - || model.equals("SM-G950U") - || model.equals("SM-G950U1") - || model.equals("SM-G950W")))) { - return "Galaxy S8"; - } - if ((codename != null && (codename.equals("SC-03J") - || codename.equals("SCV35") - || codename.equals("dream2lte") - || codename.equals("dream2lteks") - || codename.equals("dream2qltecan") - || codename.equals("dream2qltechn") - || codename.equals("dream2qltesq") - || codename.equals("dream2qlteue"))) || (model != null && (model.equals("SC-03J") - || model.equals("SCV35") - || model.equals("SM-G9550") - || model.equals("SM-G955F") - || model.equals("SM-G955N") - || model.equals("SM-G955U") - || model.equals("SM-G955U1") - || model.equals("SM-G955W")))) { - return "Galaxy S8+"; - } - if ((codename != null && (codename.equals("SC-02K") - || codename.equals("SCV38") - || codename.equals("starlte") - || codename.equals("starlteks") - || codename.equals("starqltechn") - || codename.equals("starqltecmcc") - || codename.equals("starqltecs") - || codename.equals("starqltesq") - || codename.equals("starqlteue"))) || (model != null && (model.equals("SC-02K") - || model.equals("SCV38") - || model.equals("SM-G9600") - || model.equals("SM-G9608") - || model.equals("SM-G960F") - || model.equals("SM-G960N") - || model.equals("SM-G960U") - || model.equals("SM-G960U1") - || model.equals("SM-G960W")))) { - return "Galaxy S9"; - } - if ((codename != null && (codename.equals("SC-03K") - || codename.equals("SCV39") - || codename.equals("star2lte") - || codename.equals("star2lteks") - || codename.equals("star2qltechn") - || codename.equals("star2qltecs") - || codename.equals("star2qltesq") - || codename.equals("star2qlteue"))) || (model != null && (model.equals("SC-03K") - || model.equals("SCV39") - || model.equals("SM-G9650") - || model.equals("SM-G965F") - || model.equals("SM-G965N") - || model.equals("SM-G965U") - || model.equals("SM-G965U1") - || model.equals("SM-G965W")))) { - return "Galaxy S9+"; - } - // ---------------------------------------------------------------------------- - // Sony - if ((codename != null && (codename.equals("802SO") - || codename.equals("J8110") - || codename.equals("J8170") - || codename.equals("J9110") - || codename.equals("SO-03L") - || codename.equals("SOV40"))) || (model != null && (model.equals("802SO") - || model.equals("J8110") - || model.equals("J8170") - || model.equals("J9110") - || model.equals("SO-03L") - || model.equals("SOV40")))) { - return "Xperia 1"; - } - if ((codename != null && (codename.equals("I3113") - || codename.equals("I3123") - || codename.equals("I4113") - || codename.equals("I4193"))) || (model != null && (model.equals("I3113") - || model.equals("I3123") - || model.equals("I4113") - || model.equals("I4193")))) { - return "Xperia 10"; - } - if ((codename != null && (codename.equals("I3213") - || codename.equals("I3223") - || codename.equals("I4213") - || codename.equals("I4293"))) || (model != null && (model.equals("I3213") - || model.equals("I3223") - || model.equals("I4213") - || model.equals("I4293")))) { - return "Xperia 10 Plus"; - } - if ((codename != null && (codename.equals("702SO") - || codename.equals("H8216") - || codename.equals("H8266") - || codename.equals("H8276") - || codename.equals("H8296") - || codename.equals("SO-03K") - || codename.equals("SOV37"))) || (model != null && (model.equals("702SO") - || model.equals("H8216") - || model.equals("H8266") - || model.equals("H8276") - || model.equals("H8296") - || model.equals("SO-03K") - || model.equals("SOV37")))) { - return "Xperia XZ2"; - } - if ((codename != null && (codename.equals("H8116") - || codename.equals("H8166") - || codename.equals("SO-04K") - || codename.equals("SOV38"))) || (model != null && (model.equals("H8116") - || model.equals("H8166") - || model.equals("SO-04K") - || model.equals("SOV38")))) { - return "Xperia XZ2 Premium"; - } - if ((codename != null && (codename.equals("801SO") - || codename.equals("H8416") - || codename.equals("H9436") - || codename.equals("H9493") - || codename.equals("SO-01L") - || codename.equals("SOV39"))) || (model != null && (model.equals("801SO") - || model.equals("H8416") - || model.equals("H9436") - || model.equals("H9493") - || model.equals("SO-01L") - || model.equals("SOV39")))) { - return "Xperia XZ3"; - } - return fallback; - } - - /** - * Get the {@link DeviceInfo} for the current device. Do not run on the UI thread, as this may - * download JSON to retrieve the {@link DeviceInfo}. JSON is only downloaded once and then - * stored to {@link SharedPreferences}. - * - * @param context the application context. - * @return {@link DeviceInfo} for the current device. - */ - @WorkerThread public static DeviceInfo getDeviceInfo(Context context) { - return getDeviceInfo(context.getApplicationContext(), Build.DEVICE, Build.MODEL); - } - - /** - * Get the {@link DeviceInfo} for the current device. Do not run on the UI thread, as this may - * download JSON to retrieve the {@link DeviceInfo}. JSON is only downloaded once and then - * stored to {@link SharedPreferences}. - * - * @param context the application context. - * @param codename the codename of the device - * @return {@link DeviceInfo} for the current device. - */ - @WorkerThread public static DeviceInfo getDeviceInfo(Context context, String codename) { - return getDeviceInfo(context, codename, null); - } - - /** - * Get the {@link DeviceInfo} for the current device. Do not run on the UI thread, as this may - * download JSON to retrieve the {@link DeviceInfo}. JSON is only downloaded once and then - * stored to {@link SharedPreferences}. - * - * @param context the application context. - * @param codename the codename of the device - * @param model the model of the device - * @return {@link DeviceInfo} for the current device. - */ - @WorkerThread public static DeviceInfo getDeviceInfo(Context context, String codename, String model) { - SharedPreferences prefs = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE); - String key = String.format("%s:%s", codename, model); - String savedJson = prefs.getString(key, null); - if (savedJson != null) { - try { - return new DeviceInfo(new JSONObject(savedJson)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - // check if we have an internet connection - int ret = context.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE); - boolean isConnectedToNetwork = false; - if (ret == PackageManager.PERMISSION_GRANTED) { - ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - @SuppressLint("MissingPermission") NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); - if (networkInfo != null && networkInfo.isConnected()) { - isConnectedToNetwork = true; - } - } else { - // assume we are connected. - isConnectedToNetwork = true; - } - - if (isConnectedToNetwork) { - try { - // Get the device name from the generated JSON files created from Google's device list. - String url = String.format(DEVICE_JSON_URL, codename.toLowerCase(Locale.ENGLISH)); - String jsonString = downloadJson(url); - JSONArray jsonArray = new JSONArray(jsonString); - for (int i = 0, len = jsonArray.length(); i < len; i++) { - JSONObject json = jsonArray.getJSONObject(i); - DeviceInfo info = new DeviceInfo(json); - if ((codename.equalsIgnoreCase(info.codename) && model == null) - || codename.equalsIgnoreCase(info.codename) && model.equalsIgnoreCase(info.model)) { - // Save to SharedPreferences so we don't need to make another request. - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(key, json.toString()); - editor.apply(); - return info; - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (codename.equals(Build.DEVICE) && Build.MODEL.equals(model)) { - return new DeviceInfo(Build.MANUFACTURER, getDeviceName(), codename, model); // current device - } - - return new DeviceInfo(null, null, codename, model); // unknown device - } - - /** - *Capitalizes getAllProcesses the whitespace separated words in a String. Only the first - * letter of each word is changed.
- * - * Whitespace is defined by {@link Character#isWhitespace(char)}. - * - * @param str the String to capitalize - * @return capitalized The capitalized String - */ - private static String capitalize(String str) { - if (TextUtils.isEmpty(str)) { - return str; - } - char[] arr = str.toCharArray(); - boolean capitalizeNext = true; - String phrase = ""; - for (char c : arr) { - if (capitalizeNext && Character.isLetter(c)) { - phrase += Character.toUpperCase(c); - capitalizeNext = false; - continue; - } else if (Character.isWhitespace(c)) { - capitalizeNext = true; - } - phrase += c; - } - return phrase; - } - - /** Download URL to String */ - @WorkerThread private static String downloadJson(String myurl) throws IOException { - StringBuilder sb = new StringBuilder(); - BufferedReader reader = null; - try { - URL url = new URL(myurl); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setReadTimeout(10000); - conn.setConnectTimeout(15000); - conn.setRequestMethod("GET"); - conn.setDoInput(true); - conn.connect(); - if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { - reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String line; - while ((line = reader.readLine()) != null) { - sb.append(line).append('\n'); - } - } - return sb.toString(); - } finally { - if (reader != null) { - reader.close(); - } - } - } - - public static final class Request { - - final Context context; - final Handler handler; - String codename; - String model; - - private Request(Context ctx) { - context = ctx; - handler = new Handler(ctx.getMainLooper()); - } - - /** - * Set the device codename to query. You should also set the model. - * - * @param codename the value of the system property "ro.product.device" - * @return This Request object to allow for chaining of calls to set methods. - * @see Build#DEVICE - */ - public Request setCodename(String codename) { - this.codename = codename; - return this; - } - - /** - * Set the device model to query. You should also set the codename. - * - * @param model the value of the system property "ro.product.model" - * @return This Request object to allow for chaining of calls to set methods. - * @see Build#MODEL - */ - public Request setModel(String model) { - this.model = model; - return this; - } - - /** - * Download information about the device. This saves the results in shared-preferences so - * future requests will not need a network connection. - * - * @param callback the callback to retrieve the {@link DeviceName.DeviceInfo} - */ - public void request(Callback callback) { - if (codename == null && model == null) { - codename = Build.DEVICE; - model = Build.MODEL; - } - GetDeviceRunnable runnable = new GetDeviceRunnable(callback); - if (Looper.myLooper() == Looper.getMainLooper()) { - new Thread(runnable).start(); - } else { - runnable.run(); // already running in background thread. - } - } - - private final class GetDeviceRunnable implements Runnable { - - final Callback callback; - DeviceInfo deviceInfo; - Exception error; - - public GetDeviceRunnable(Callback callback) { - this.callback = callback; - } - - @Override public void run() { - try { - deviceInfo = getDeviceInfo(context, codename, model); - } catch (Exception e) { - error = e; - } - handler.post(new Runnable() { - - @Override public void run() { - callback.onFinished(deviceInfo, error); - } - }); - } - } - } - - /** - * Callback which is invoked when the {@link DeviceName.DeviceInfo} is finished loading. - */ - public interface Callback { - - /** - * Callback to get the device info. This is run on the UI thread. - * - * @param info the requested {@link DeviceName.DeviceInfo} - * @param error {@code null} if nothing went wrong. - */ - void onFinished(DeviceInfo info, Exception error); - } - - /** - * Device information based on - * Google's maintained list. - */ - public static final class DeviceInfo { - - /** Retail branding */ - public final String manufacturer; - - /** Marketing name */ - public final String marketName; - - /** the value of the system property "ro.product.device" */ - public final String codename; - - /** the value of the system property "ro.product.model" */ - public final String model; - - public DeviceInfo(String manufacturer, String marketName, String codename, String model) { - this.manufacturer = manufacturer; - this.marketName = marketName; - this.codename = codename; - this.model = model; - } - - private DeviceInfo(JSONObject jsonObject) throws JSONException { - manufacturer = jsonObject.getString("manufacturer"); - marketName = jsonObject.getString("market_name"); - codename = jsonObject.getString("codename"); - model = jsonObject.getString("model"); - } - - /** - * @return the consumer friendly name of the device. - */ - public String getName() { - if (!TextUtils.isEmpty(marketName)) { - return marketName; - } - return capitalize(model); - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/DeviceName.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/DeviceName.kt new file mode 100644 index 000000000..ee634fb33 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/DeviceName.kt @@ -0,0 +1,573 @@ +package com.habitrpg.android.habitica.helpers + +import android.Manifest +import android.annotation.SuppressLint +import android.content.Context +import android.content.SharedPreferences +import android.content.pm.PackageManager +import android.net.ConnectivityManager +import android.os.Build +import android.os.Handler +import android.os.Looper +import android.text.TextUtils +import androidx.annotation.WorkerThread +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.net.HttpURLConnection +import java.net.URL +import java.util.* + +/* +* Copyright (C) 2017 Jared Rummler +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ // @formatter:off +/** + * + * Get the consumer friendly name of an Android device. + * + * + * On many popular devices the market name of the device is not available. For example, on the + * Samsung Galaxy S6 the value of [Build.MODEL] could be "SM-G920F", "SM-G920I", "SM-G920W8", + * etc. + * + * + * See the usages below to get the consumer friends name of a device: + * + * + * **Get the name of the current device:** + * + *+ * String deviceName = DeviceName.getDeviceName(); +* + * + * + * The above code will get the correct device name for the top 600 Android devices. If the + * device is unrecognized, then Build.MODEL is returned. + * + * + * **Get the name of a device using the device's codename:** + * + *
+ * // Retruns "Moto X Style"
+ * DeviceName.getDeviceName("clark", "Unknown device");
+ *
+ *
+ *
+ * **Get information about the device:**
+ *
+ *
+ * DeviceName.with(context).request(new DeviceName.Callback() {
+ *
+ * @Override public void onFinished(DeviceName.DeviceInfo info, Exception error) {
+ * String manufacturer = info.manufacturer; // "Samsung"
+ * String name = info.marketName; // "Galaxy S6 Edge"
+ * String model = info.model; // "SM-G925I"
+ * String codename = info.codename; // "zerolte"
+ * String deviceName = info.getName(); // "Galaxy S6 Edge"
+ * // FYI: We are on the UI thread.
+ * }
+ * });
+ *
+ *
+ *
+ * The above code loads JSON from a generated list of device names based on Google's maintained
+ * list. It will be up-to-date with Google's supported device list so that you will get the correct
+ * name for new or unknown devices. This supports over 10,000 devices.
+ *
+ *
+ * This will only make a network call once. The value is saved to SharedPreferences for future
+ * calls.
+ */
+object DeviceName {
+ // @formatter:on
+ // JSON which is derived from Google's PDF document which contains all devices on Google Play.
+ // To get the URL to the JSON file which contains information about the device name:
+ // String url = String.format(DEVICE_JSON_URL, Build.DEVICE);
+ private const val DEVICE_JSON_URL = "https://raw.githubusercontent.com/jaredrummler/AndroidDeviceNames/master/json/devices/%s.json"
+
+ // Preference filename for storing device info so we don't need to download it again.
+ private const val SHARED_PREF_NAME = "device_names"
+
+ /**
+ * Create a new request to get information about a device.
+ *
+ * @param context the application context
+ * @return a new Request instance.
+ */
+ fun with(context: Context): Request {
+ return Request(context.applicationContext)
+ }
+
+ /**
+ * Get the consumer friendly name of the device.
+ *
+ * @return the market name of the current device.
+ * @see .getDeviceName
+ */
+ val deviceName: String?
+ get() = getDeviceName(Build.DEVICE, Build.MODEL, Build.MODEL.capitalize(Locale.getDefault()))
+
+ /**
+ * Get the consumer friendly name of a device.
+ *
+ * @param codename the value of the system property "ro.product.device" ([Build.DEVICE])
+ * *or*
+ * the value of the system property "ro.product.model" ([Build.MODEL])
+ * @param fallback the fallback name if the device is unknown. Usually the value of the system property
+ * "ro.product.model" ([Build.MODEL])
+ * @return the market name of a device or `fallback` if the device is unknown.
+ */
+ fun getDeviceName(codename: String?, fallback: String?): String? {
+ return getDeviceName(codename, codename, fallback)
+ }
+
+ /**
+ * Get the consumer friendly name of a device.
+ *
+ * @param codename the value of the system property "ro.product.device" ([Build.DEVICE]).
+ * @param model the value of the system property "ro.product.model" ([Build.MODEL]).
+ * @param fallback the fallback name if the device is unknown. Usually the value of the system property
+ * "ro.product.model" ([Build.MODEL])
+ * @return the market name of a device or `fallback` if the device is unknown.
+ */
+ fun getDeviceName(codename: String?, model: String?, fallback: String?): String? {
+ // ----------------------------------------------------------------------------
+ // Google
+ if (codename != null && codename == "walleye") {
+ return "Pixel 2"
+ }
+ if (codename != null && codename == "taimen") {
+ return "Pixel 2 XL"
+ }
+ if (codename != null && codename == "blueline") {
+ return "Pixel 3"
+ }
+ if (codename != null && codename == "crosshatch") {
+ return "Pixel 3 XL"
+ }
+ if (codename != null && codename == "sargo") {
+ return "Pixel 3a"
+ }
+ if (codename != null && codename == "bonito") {
+ return "Pixel 3a XL"
+ }
+ // ----------------------------------------------------------------------------
+ // Huawei
+ if (codename != null && codename == "HWBND-H" || model != null && (model == "BND-L21" || model == "BND-L24" || model == "BND-L31")) {
+ return "Honor 7X"
+ }
+ if (codename != null && codename == "HWBKL" || model != null && (model == "BKL-L04" || model ==
+ "BKL-L09")) {
+ return "Honor View 10"
+ }
+ if (codename != null && codename == "HWALP" || model != null && (model == "ALP-AL00" || model ==
+ "ALP-L09" || model == "ALP-L29" || model == "ALP-TL00")) {
+ return "Mate 10"
+ }
+ if (codename != null && codename == "HWMHA" || model != null && (model == "MHA-AL00" || model ==
+ "MHA-L09" || model == "MHA-L29" || model == "MHA-TL00")) {
+ return "Mate 9"
+ }
+ if (codename != null && codename == "angler") {
+ return "Nexus 6P"
+ }
+ // ----------------------------------------------------------------------------
+ // LGE
+ if (codename != null && codename == "h1" || model != null && (model == "LG-F700K" || model ==
+ "LG-F700L" || model == "LG-F700S" || model == "LG-H820" || model == "LG-H820PR" || model ==
+ "LG-H830" || model == "LG-H831" || model == "LG-H850" || model == "LG-H858" || model ==
+ "LG-H860" || model == "LG-H868" || model == "LGAS992" || model == "LGLS992" || model ==
+ "LGUS992" || model == "RS988" || model == "VS987")) {
+ return "LG G5"
+ }
+ if (codename != null && codename == "lucye" || model != null && (model == "LG-AS993" || model == "LG-H870" || model == "LG-H870AR" || model == "LG-H870DS" || model == "LG-H870I" || model == "LG-H870S" || model == "LG-H871" || model == "LG-H871S" || model == "LG-H872" || model == "LG-H872PR" || model == "LG-H873" || model == "LG-LS993" || model == "LGM-G600K" || model == "LGM-G600L" || model == "LGM-G600S" || model == "LGUS997" || model == "VS988")) {
+ return "LG G6"
+ }
+ if (codename != null && codename == "flashlmdd" || model != null && (model == "LM-V500" || model == "LM-V500N")) {
+ return "LG V50 ThinQ"
+ }
+ if (codename != null && codename == "mako") {
+ return "Nexus 4"
+ }
+ if (codename != null && codename == "hammerhead") {
+ return "Nexus 5"
+ }
+ if (codename != null && codename == "bullhead") {
+ return "Nexus 5X"
+ }
+ // ----------------------------------------------------------------------------
+ // Motorola
+ if (codename != null && codename == "griffin" || model != null && (model == "XT1650" || model ==
+ "XT1650-05")) {
+ return "Moto Z"
+ }
+ if (codename != null && codename == "shamu") {
+ return "Nexus 6"
+ }
+ // ----------------------------------------------------------------------------
+ // Nokia
+ if (codename != null && (codename == "RHD" || codename == "ROO" || codename == "ROON_sprout" || codename == "ROO_sprout")) {
+ return "Nokia 3.1 Plus"
+ }
+ if (codename != null && codename == "CTL_sprout") {
+ return "Nokia 7.1"
+ }
+ // ----------------------------------------------------------------------------
+ // OnePlus
+ if (codename != null && codename == "OnePlus6" || model != null && model == "ONEPLUS A6003") {
+ return "OnePlus 6"
+ }
+ if (codename != null && (codename == "OnePlus6T" || codename == "OnePlus6TSingle") || (model != null
+ && model == "ONEPLUS A6013")) {
+ return "OnePlus 6T"
+ }
+ if (codename != null && codename == "OnePlus7" || model != null && model == "GM1905") {
+ return "OnePlus 7"
+ }
+ if (codename != null && (codename == "OnePlus7Pro" || codename == "OnePlus7ProTMO") || (model != null
+ && (model == "GM1915" || model == "GM1917"))) {
+ return "OnePlus 7 Pro"
+ }
+ // ----------------------------------------------------------------------------
+ // Samsung
+ if (codename != null && codename == "a50" || model != null && (model == "SM-A505F" || model == "SM-A505FM" || model == "SM-A505FN" || model == "SM-A505G" || model == "SM-A505GN" || model == "SM-A505GT" || model == "SM-A505N" || model == "SM-A505U" || model == "SM-A505W" || model == "SM-A505YN")) {
+ return "Galaxy A50"
+ }
+ if (codename != null && (codename == "a6elteaio" || codename == "a6elteatt" || codename == "a6eltemtr" || codename == "a6eltespr" || codename == "a6eltetmo" || codename == "a6elteue" || codename == "a6lte" || codename == "a6lteks") || model != null && (model == "SM-A600A" || model == "SM-A600AZ" || model == "SM-A600F" || model == "SM-A600FN" || model == "SM-A600G" || model == "SM-A600GN" || model == "SM-A600N" || model == "SM-A600P" || model == "SM-A600T" || model == "SM-A600T1" || model == "SM-A600U")) {
+ return "Galaxy A6"
+ }
+ if (codename != null && (codename == "SC-01J" || codename == "SCV34" || codename == "gracelte" || codename == "graceltektt" || codename == "graceltelgt" || codename == "gracelteskt" || codename == "graceqlteacg" || codename == "graceqlteatt" || codename == "graceqltebmc" || codename == "graceqltechn" || codename == "graceqltedcm" || codename == "graceqltelra" || codename == "graceqltespr" || codename == "graceqltetfnvzw" || codename == "graceqltetmo" || codename == "graceqlteue" || codename == "graceqlteusc" || codename == "graceqltevzw") || model != null && (model == "SAMSUNG-SM-N930A" || model == "SC-01J" || model == "SCV34" || model == "SGH-N037" || model == "SM-N9300" || model == "SM-N930F" || model == "SM-N930K" || model == "SM-N930L" || model == "SM-N930P" || model == "SM-N930R4" || model == "SM-N930R6" || model == "SM-N930R7" || model == "SM-N930S" || model == "SM-N930T" || model == "SM-N930U" || model == "SM-N930V" || model == "SM-N930VL" || model == "SM-N930W8" || model == "SM-N930X")) {
+ return "Galaxy Note7"
+ }
+ if (codename != null && (codename == "SC-01K" || codename == "SCV37" || codename == "greatlte" || codename == "greatlteks" || codename == "greatqlte" || codename == "greatqltechn" || codename == "greatqltecmcc" || codename == "greatqltecs" || codename == "greatqlteue") || model != null && (model == "SC-01K" || model == "SCV37" || model == "SM-N9500" || model == "SM-N9508" || model == "SM-N950F" || model == "SM-N950N" || model == "SM-N950U" || model == "SM-N950U1" || model == "SM-N950W" || model == "SM-N950XN")) {
+ return "Galaxy Note8"
+ }
+ if (codename != null && (codename == "SC-01L" || codename == "SCV40" || codename == "crownlte" || codename == "crownlteks" || codename == "crownqltechn" || codename == "crownqltecs" || codename == "crownqltesq" || codename == "crownqlteue") || model != null && (model == "SC-01L" || model == "SCV40" || model == "SM-N9600" || model == "SM-N960F" || model == "SM-N960N" || model == "SM-N960U" || model == "SM-N960U1" || model == "SM-N960W")) {
+ return "Galaxy Note9"
+ }
+ if (codename != null && (codename == "SC-03L" || codename == "SCV41" || codename == "beyond1" || codename == "beyond1q") || model != null && (model == "SC-03L" || model == "SCV41" || model == "SM-G9730" || model == "SM-G9738" || model == "SM-G973F" || model == "SM-G973N" || model == "SM-G973U" || model == "SM-G973U1" || model == "SM-G973W")) {
+ return "Galaxy S10"
+ }
+ if (codename != null && (codename == "SC-04L" || codename == "SCV42" || codename == "beyond2" || codename == "beyond2q") || model != null && (model == "SC-04L" || model == "SCV42" || model == "SM-G9750" || model == "SM-G9758" || model == "SM-G975F" || model == "SM-G975N" || model == "SM-G975U" || model == "SM-G975U1" || model == "SM-G975W")) {
+ return "Galaxy S10+"
+ }
+ if (codename != null && (codename == "beyond0" || codename == "beyond0q") || (model != null
+ && (model == "SM-G9700" || model == "SM-G9708" || model == "SM-G970F" || model == "SM-G970N" || model == "SM-G970U" || model == "SM-G970U1" || model == "SM-G970W"))) {
+ return "Galaxy S10e"
+ }
+ if (codename != null && (codename == "SC-04F" || codename == "SCL23" || codename == "k3g" || codename == "klte" || codename == "klteMetroPCS" || codename == "klteacg" || codename == "klteaio" || codename == "klteatt" || codename == "kltecan" || codename == "klteduoszn" || codename == "kltektt" || codename == "kltelgt" || codename == "kltelra" || codename == "klteskt" || codename == "kltespr" || codename == "kltetfnvzw" || codename == "kltetmo" || codename == "klteusc" || codename == "kltevzw" || codename == "kwifi" || codename == "lentisltektt" || codename == "lentisltelgt" || codename == "lentislteskt") || model != null && (model == "SAMSUNG-SM-G900A" || model == "SAMSUNG-SM-G900AZ" || model == "SC-04F" || model == "SCL23" || model == "SM-G9006W" || model == "SM-G9008W" || model == "SM-G9009W" || model == "SM-G900F" || model == "SM-G900FQ" || model == "SM-G900H" || model == "SM-G900I" || model == "SM-G900K" || model == "SM-G900L" || model == "SM-G900M" || model == "SM-G900MD" || model == "SM-G900P" || model == "SM-G900R4" || model == "SM-G900R6" || model == "SM-G900R7" || model == "SM-G900S" || model == "SM-G900T" || model == "SM-G900T1" || model == "SM-G900T3" || model == "SM-G900T4" || model == "SM-G900V" || model == "SM-G900W8" || model == "SM-G900X" || model == "SM-G906K" || model == "SM-G906L" || model == "SM-G906S" || model == "SM-S903VL")) {
+ return "Galaxy S5"
+ }
+ if (codename != null && (codename == "s5neolte" || codename == "s5neoltecan") || model != null && (model == "SM-G903F" || model == "SM-G903M" || model == "SM-G903W")) {
+ return "Galaxy S5 Neo"
+ }
+ if (codename != null && (codename == "SC-05G" || codename == "zeroflte" || codename == "zeroflteacg" || codename == "zeroflteaio" || codename == "zeroflteatt" || codename == "zerofltebmc" || codename == "zerofltechn" || codename == "zerofltectc" || codename == "zerofltektt" || codename == "zerofltelgt" || codename == "zerofltelra" || codename == "zerofltemtr" || codename == "zeroflteskt" || codename == "zerofltespr" || codename == "zerofltetfnvzw" || codename == "zerofltetmo" || codename == "zeroflteusc" || codename == "zerofltevzw") || model != null && (model == "SAMSUNG-SM-G920A" || model == "SAMSUNG-SM-G920AZ" || model == "SC-05G" || model == "SM-G9200" || model == "SM-G9208" || model == "SM-G9209" || model == "SM-G920F" || model == "SM-G920I" || model == "SM-G920K" || model == "SM-G920L" || model == "SM-G920P" || model == "SM-G920R4" || model == "SM-G920R6" || model == "SM-G920R7" || model == "SM-G920S" || model == "SM-G920T" || model == "SM-G920T1" || model == "SM-G920V" || model == "SM-G920W8" || model == "SM-G920X" || model == "SM-S906L" || model == "SM-S907VL")) {
+ return "Galaxy S6"
+ }
+ if (codename != null && (codename == "404SC" || codename == "SC-04G" || codename == "SCV31" || codename == "zerolte" || codename == "zerolteacg" || codename == "zerolteatt" || codename == "zeroltebmc" || codename == "zeroltechn" || codename == "zeroltektt" || codename == "zeroltelra" || codename == "zerolteskt" || codename == "zeroltespr" || codename == "zeroltetmo" || codename == "zerolteusc" || codename == "zeroltevzw") || model != null && (model == "404SC" || model == "SAMSUNG-SM-G925A" || model == "SC-04G" || model == "SCV31" || model == "SM-G9250" || model == "SM-G925I" || model == "SM-G925K" || model == "SM-G925P" || model == "SM-G925R4" || model == "SM-G925R6" || model == "SM-G925R7" || model == "SM-G925S" || model == "SM-G925T" || model == "SM-G925V" || model == "SM-G925W8" || model == "SM-G925X")) {
+ return "Galaxy S6 Edge"
+ }
+ if (codename != null && (codename == "zenlte" || codename == "zenlteatt" || codename == "zenltebmc" || codename == "zenltechn" || codename == "zenltektt" || codename == "zenltekx" || codename == "zenltelgt" || codename == "zenlteskt" || codename == "zenltespr" || codename == "zenltetmo" || codename == "zenlteusc" || codename == "zenltevzw") || model != null && (model == "SAMSUNG-SM-G928A" || model == "SM-G9280" || model == "SM-G9287C" || model == "SM-G928C" || model == "SM-G928G" || model == "SM-G928I" || model == "SM-G928K" || model == "SM-G928L" || model == "SM-G928N0" || model == "SM-G928P" || model == "SM-G928R4" || model == "SM-G928S" || model == "SM-G928T" || model == "SM-G928V" || model == "SM-G928W8" || model == "SM-G928X")) {
+ return "Galaxy S6 Edge+"
+ }
+ if (codename != null && (codename == "herolte" || codename == "heroltebmc" || codename ==
+ "heroltektt" || codename == "heroltelgt" || codename == "herolteskt" || codename ==
+ "heroqlteacg" || codename == "heroqlteaio" || codename == "heroqlteatt" || codename ==
+ "heroqltecctvzw" || codename == "heroqltechn" || codename == "heroqltelra" || codename ==
+ "heroqltemtr" || codename == "heroqltespr" || codename == "heroqltetfnvzw" || codename ==
+ "heroqltetmo" || codename == "heroqlteue" || codename == "heroqlteusc" || codename ==
+ "heroqltevzw") || model != null && (model == "SAMSUNG-SM-G930A" || model == "SAMSUNG-SM-G930AZ" || model == "SM-G9300" || model == "SM-G9308" || model == "SM-G930F" || model == "SM-G930K" || model == "SM-G930L" || model == "SM-G930P" || model == "SM-G930R4" || model == "SM-G930R6" || model == "SM-G930R7" || model == "SM-G930S" || model == "SM-G930T" || model == "SM-G930T1" || model == "SM-G930U" || model == "SM-G930V" || model == "SM-G930VC" || model == "SM-G930VL" || model == "SM-G930W8" || model == "SM-G930X")) {
+ return "Galaxy S7"
+ }
+ if (codename != null && (codename == "SC-02H" || codename == "SCV33" || codename == "hero2lte" || codename == "hero2ltebmc" || codename == "hero2ltektt" || codename == "hero2lteskt" || codename == "hero2qlteatt" || codename == "hero2qltecctvzw" || codename == "hero2qltespr" || codename == "hero2qltetmo" || codename == "hero2qlteusc" || codename == "hero2qltevzw") || model != null && (model == "SAMSUNG-SM-G935A" || model == "SC-02H" || model == "SCV33" || model == "SM-G935K" || model == "SM-G935P" || model == "SM-G935R4" || model == "SM-G935S" || model == "SM-G935T" || model == "SM-G935V" || model == "SM-G935VC" || model == "SM-G935W8" || model == "SM-G935X")) {
+ return "Galaxy S7 Edge"
+ }
+ if (codename != null && (codename == "SC-02J" || codename == "SCV36" || codename == "dreamlte" || codename == "dreamlteks" || codename == "dreamqltecan" || codename == "dreamqltechn" || codename == "dreamqltecmcc" || codename == "dreamqltesq" || codename == "dreamqlteue") || model != null && (model == "SC-02J" || model == "SCV36" || model == "SM-G9500" || model == "SM-G9508" || model == "SM-G950F" || model == "SM-G950N" || model == "SM-G950U" || model == "SM-G950U1" || model == "SM-G950W")) {
+ return "Galaxy S8"
+ }
+ if (codename != null && (codename == "SC-03J" || codename == "SCV35" || codename == "dream2lte" || codename == "dream2lteks" || codename == "dream2qltecan" || codename == "dream2qltechn" || codename == "dream2qltesq" || codename == "dream2qlteue") || model != null && (model == "SC-03J" || model == "SCV35" || model == "SM-G9550" || model == "SM-G955F" || model == "SM-G955N" || model == "SM-G955U" || model == "SM-G955U1" || model == "SM-G955W")) {
+ return "Galaxy S8+"
+ }
+ if (codename != null && (codename == "SC-02K" || codename == "SCV38" || codename == "starlte" || codename == "starlteks" || codename == "starqltechn" || codename == "starqltecmcc" || codename == "starqltecs" || codename == "starqltesq" || codename == "starqlteue") || model != null && (model == "SC-02K" || model == "SCV38" || model == "SM-G9600" || model == "SM-G9608" || model == "SM-G960F" || model == "SM-G960N" || model == "SM-G960U" || model == "SM-G960U1" || model == "SM-G960W")) {
+ return "Galaxy S9"
+ }
+ if (codename != null && (codename == "SC-03K" || codename == "SCV39" || codename == "star2lte" || codename == "star2lteks" || codename == "star2qltechn" || codename == "star2qltecs" || codename == "star2qltesq" || codename == "star2qlteue") || model != null && (model == "SC-03K" || model == "SCV39" || model == "SM-G9650" || model == "SM-G965F" || model == "SM-G965N" || model == "SM-G965U" || model == "SM-G965U1" || model == "SM-G965W")) {
+ return "Galaxy S9+"
+ }
+ // ----------------------------------------------------------------------------
+ // Sony
+ if (codename != null && (codename == "802SO" || codename == "J8110" || codename == "J8170" || codename == "J9110" || codename == "SO-03L" || codename == "SOV40") || model != null && (model == "802SO" || model == "J8110" || model == "J8170" || model == "J9110" || model == "SO-03L" || model == "SOV40")) {
+ return "Xperia 1"
+ }
+ if (codename != null && (codename == "I3113" || codename == "I3123" || codename == "I4113" || codename == "I4193") || model != null && (model == "I3113" || model == "I3123" || model == "I4113" || model == "I4193")) {
+ return "Xperia 10"
+ }
+ if (codename != null && (codename == "I3213" || codename == "I3223" || codename == "I4213" || codename == "I4293") || model != null && (model == "I3213" || model == "I3223" || model == "I4213" || model == "I4293")) {
+ return "Xperia 10 Plus"
+ }
+ if (codename != null && (codename == "702SO" || codename == "H8216" || codename == "H8266" || codename == "H8276" || codename == "H8296" || codename == "SO-03K" || codename == "SOV37") || model != null && (model == "702SO" || model == "H8216" || model == "H8266" || model == "H8276" || model == "H8296" || model == "SO-03K" || model == "SOV37")) {
+ return "Xperia XZ2"
+ }
+ if (codename != null && (codename == "H8116" || codename == "H8166" || codename == "SO-04K" || codename == "SOV38") || model != null && (model == "H8116" || model == "H8166" || model == "SO-04K" || model == "SOV38")) {
+ return "Xperia XZ2 Premium"
+ }
+ return if (codename != null && (codename == "801SO" || codename == "H8416" || codename == "H9436" || codename == "H9493" || codename == "SO-01L" || codename == "SOV39") || model != null && (model == "801SO" || model == "H8416" || model == "H9436" || model == "H9493" || model == "SO-01L" || model == "SOV39")) {
+ "Xperia XZ3"
+ } else fallback
+ }
+
+ /**
+ * Get the [DeviceInfo] for the current device. Do not run on the UI thread, as this may
+ * download JSON to retrieve the [DeviceInfo]. JSON is only downloaded once and then
+ * stored to [SharedPreferences].
+ *
+ * @param context the application context.
+ * @return [DeviceInfo] for the current device.
+ */
+ @WorkerThread
+ fun getDeviceInfo(context: Context): DeviceInfo {
+ return getDeviceInfo(context.applicationContext, Build.DEVICE, Build.MODEL)
+ }
+
+ /**
+ * Get the [DeviceInfo] for the current device. Do not run on the UI thread, as this may
+ * download JSON to retrieve the [DeviceInfo]. JSON is only downloaded once and then
+ * stored to [SharedPreferences].
+ *
+ * @param context the application context.
+ * @param codename the codename of the device
+ * @return [DeviceInfo] for the current device.
+ */
+ @WorkerThread
+ fun getDeviceInfo(context: Context, codename: String?): DeviceInfo {
+ return getDeviceInfo(context, codename, null)
+ }
+
+ /**
+ * Get the [DeviceInfo] for the current device. Do not run on the UI thread, as this may
+ * download JSON to retrieve the [DeviceInfo]. JSON is only downloaded once and then
+ * stored to [SharedPreferences].
+ *
+ * @param context the application context.
+ * @param codename the codename of the device
+ * @param model the model of the device
+ * @return [DeviceInfo] for the current device.
+ */
+ @WorkerThread
+ fun getDeviceInfo(context: Context, codename: String?, model: String?): DeviceInfo {
+ val prefs = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
+ val key = String.format("%s:%s", codename, model)
+ val savedJson = prefs.getString(key, null)
+ if (savedJson != null) {
+ try {
+ return DeviceInfo(JSONObject(savedJson))
+ } catch (e: JSONException) {
+ e.printStackTrace()
+ }
+ }
+
+ // check if we have an internet connection
+ val ret = context.checkCallingOrSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE)
+ var isConnectedToNetwork = false
+ if (ret == PackageManager.PERMISSION_GRANTED) {
+ val connMgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ @SuppressLint("MissingPermission") val networkInfo = connMgr.activeNetworkInfo
+ if (networkInfo != null && networkInfo.isConnected) {
+ isConnectedToNetwork = true
+ }
+ } else {
+ // assume we are connected.
+ isConnectedToNetwork = true
+ }
+ if (isConnectedToNetwork) {
+ try {
+ // Get the device name from the generated JSON files created from Google's device list.
+ val url = String.format(DEVICE_JSON_URL, codename!!.toLowerCase(Locale.ENGLISH))
+ val jsonString = downloadJson(url)
+ val jsonArray = JSONArray(jsonString)
+ var i = 0
+ val len = jsonArray.length()
+ while (i < len) {
+ val json = jsonArray.getJSONObject(i)
+ val info = DeviceInfo(json)
+ if (codename.equals(info.codename, ignoreCase = true) && model == null
+ || codename.equals(info.codename, ignoreCase = true) && model.equals(info.model, ignoreCase = true)) {
+ // Save to SharedPreferences so we don't need to make another request.
+ val editor = prefs.edit()
+ editor.putString(key, json.toString())
+ editor.apply()
+ return info
+ }
+ i++
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ return if (codename == Build.DEVICE && Build.MODEL == model) {
+ DeviceInfo(Build.MANUFACTURER, deviceName, codename, model) // current device
+ } else DeviceInfo(null, null, codename, model)
+ // unknown device
+ }
+
+ /** Download URL to String */
+ @WorkerThread
+ @Throws(IOException::class)
+ private fun downloadJson(myurl: String): String {
+ val sb = StringBuilder()
+ var reader: BufferedReader? = null
+ return try {
+ val url = URL(myurl)
+ val conn = url.openConnection() as HttpURLConnection
+ conn.readTimeout = 10000
+ conn.connectTimeout = 15000
+ conn.requestMethod = "GET"
+ conn.doInput = true
+ conn.connect()
+ if (conn.responseCode == HttpURLConnection.HTTP_OK) {
+ reader = BufferedReader(InputStreamReader(conn.inputStream))
+ var line: String?
+ while (reader.readLine().also { line = it } != null) {
+ sb.append(line).append('\n')
+ }
+ }
+ sb.toString()
+ } finally {
+ reader?.close()
+ }
+ }
+
+ class Request internal constructor(val context: Context) {
+ val handler: Handler
+ var codename: String? = null
+ var model: String? = null
+
+ /**
+ * Set the device codename to query. You should also set the model.
+ *
+ * @param codename the value of the system property "ro.product.device"
+ * @return This Request object to allow for chaining of calls to set methods.
+ * @see Build.DEVICE
+ */
+ fun setCodename(codename: String?): Request {
+ this.codename = codename
+ return this
+ }
+
+ /**
+ * Set the device model to query. You should also set the codename.
+ *
+ * @param model the value of the system property "ro.product.model"
+ * @return This Request object to allow for chaining of calls to set methods.
+ * @see Build.MODEL
+ */
+ fun setModel(model: String?): Request {
+ this.model = model
+ return this
+ }
+
+ /**
+ * Download information about the device. This saves the results in shared-preferences so
+ * future requests will not need a network connection.
+ *
+ * @param callback the callback to retrieve the [DeviceName.DeviceInfo]
+ */
+ fun request(callback: Callback) {
+ if (codename == null && model == null) {
+ codename = Build.DEVICE
+ model = Build.MODEL
+ }
+ val runnable = GetDeviceRunnable(callback)
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ Thread(runnable).start()
+ } else {
+ runnable.run() // already running in background thread.
+ }
+ }
+
+ private inner class GetDeviceRunnable(val callback: Callback) : Runnable {
+ var deviceInfo: DeviceInfo? = null
+ var error: Exception? = null
+ override fun run() {
+ try {
+ deviceInfo = getDeviceInfo(context, codename, model)
+ } catch (e: Exception) {
+ error = e
+ }
+ handler.post { callback.onFinished(deviceInfo, error) }
+ }
+ }
+
+ init {
+ handler = Handler(context.mainLooper)
+ }
+ }
+
+ /**
+ * Callback which is invoked when the [DeviceName.DeviceInfo] is finished loading.
+ */
+ interface Callback {
+ /**
+ * Callback to get the device info. This is run on the UI thread.
+ *
+ * @param info the requested [DeviceName.DeviceInfo]
+ * @param error `null` if nothing went wrong.
+ */
+ fun onFinished(info: DeviceInfo?, error: Exception?)
+ }
+
+ /**
+ * Device information based on
+ * [Google's maintained list](https://support.google.com/googleplay/answer/1727131).
+ */
+ class DeviceInfo {
+ /** Retail branding */
+ val manufacturer: String?
+
+ /** Marketing name */
+ val marketName: String?
+
+ /** the value of the system property "ro.product.device" */
+ val codename: String?
+
+ /** the value of the system property "ro.product.model" */
+ val model: String?
+
+ constructor(manufacturer: String?, marketName: String?, codename: String?, model: String?) {
+ this.manufacturer = manufacturer
+ this.marketName = marketName
+ this.codename = codename
+ this.model = model
+ }
+
+ constructor(jsonObject: JSONObject) {
+ manufacturer = jsonObject.getString("manufacturer")
+ marketName = jsonObject.getString("market_name")
+ codename = jsonObject.getString("codename")
+ model = jsonObject.getString("model")
+ }
+
+ /**
+ * @return the consumer friendly name of the device.
+ */
+ val name: String?
+ get() = if (!TextUtils.isEmpty(marketName)) {
+ marketName
+ } else model?.capitalize(Locale.getDefault())
+ }
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/LanguageHelper.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/LanguageHelper.kt
index eb734a4c6..31c9e4f78 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/LanguageHelper.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/LanguageHelper.kt
@@ -4,13 +4,13 @@ import java.util.*
class LanguageHelper(languageSharedPref: String?) {
- var locale: Locale? = null
+ var locale: Locale
private set
var languageCode: String? = null
private set
init {
- when (languageSharedPref) {
+ when (val pref = languageSharedPref ?: "en") {
"iw" -> {
locale = Locale("iw")
languageCode = "he"
@@ -28,13 +28,11 @@ class LanguageHelper(languageSharedPref: String?) {
languageCode = "pt"
}
else -> {
- languageSharedPref?.let { pref ->
- locale = if (pref.contains("_")) {
- val languageCodeParts = pref.split("_".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
- Locale(languageCodeParts[0], languageCodeParts[1])
- } else {
- Locale(languageSharedPref)
- }
+ locale = if (pref.contains("_")) {
+ val languageCodeParts = pref.split("_".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ Locale(languageCodeParts[0], languageCodeParts[1])
+ } else {
+ Locale(pref)
}
languageCode = languageSharedPref
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/MainNavigationController.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/MainNavigationController.kt
index f90bb8e51..dcbf71eca 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/MainNavigationController.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/MainNavigationController.kt
@@ -1,6 +1,7 @@
package com.habitrpg.android.habitica.helpers
import android.os.Bundle
+import android.util.Log
import androidx.navigation.NavController
import androidx.navigation.NavDirections
import java.lang.ref.WeakReference
@@ -21,7 +22,11 @@ object MainNavigationController {
lastNavigation = Date()
try {
navController?.get()?.navigate(transactionId, args)
- } catch (_: IllegalArgumentException) {}
+ } catch (e: IllegalArgumentException) {
+ Log.e("Main Navigation", e.localizedMessage)
+ } catch (error: Exception) {
+ Log.e("Main Navigation", error.localizedMessage)
+ }
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/NotificationsManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/NotificationsManager.kt
index fb06fd50f..1475dd55c 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/NotificationsManager.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/NotificationsManager.kt
@@ -1,7 +1,6 @@
package com.habitrpg.android.habitica.helpers
import android.content.Context
-import androidx.core.os.bundleOf
import com.google.firebase.analytics.FirebaseAnalytics
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.ApiClient
@@ -15,13 +14,9 @@ import com.habitrpg.android.habitica.models.notifications.FirstDropData
import com.habitrpg.android.habitica.models.notifications.LoginIncentiveData
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar
-import com.habitrpg.android.habitica.ui.views.dialogs.AchievementDialog
import io.reactivex.BackpressureStrategy
import io.reactivex.Completable
import io.reactivex.Flowable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.functions.Action
-import io.reactivex.functions.Consumer
import io.reactivex.subjects.BehaviorSubject
import org.greenrobot.eventbus.EventBus
import java.util.*
@@ -116,7 +111,7 @@ class NotificationsManager (private val context: Context) {
EventBus.getDefault().post(event)
if (apiClient != null) {
apiClient?.readNotification(notification.id)
- ?.subscribe(Consumer {}, RxErrorHandler.handleEmptyError())
+ ?.subscribe({}, RxErrorHandler.handleEmptyError())
}
}
return true
@@ -131,7 +126,7 @@ class NotificationsManager (private val context: Context) {
}
val sub = Completable.complete()
.delay(delay, TimeUnit.MILLISECONDS)
- .subscribe(Action {
+ .subscribe({
EventBus.getDefault().post(ShowAchievementDialog(achievement, notification.id, isLastOnboardingAchievement))
}, RxErrorHandler.handleEmptyError())
logOnboardingEvents(achievement)
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt
index 35713840b..e2270b20e 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/PurchaseHandler.kt
@@ -5,9 +5,7 @@ import android.content.Intent
import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.proxy.CrashlyticsProxy
import org.solovyev.android.checkout.*
-import java.lang.NullPointerException
import java.util.*
-import javax.annotation.Nonnull
class PurchaseHandler(activity: Activity, val crashlyticsProxy: CrashlyticsProxy) {
private val billing = HabiticaBaseApplication.getInstance(activity.applicationContext)?.billing
@@ -121,7 +119,7 @@ class PurchaseHandler(activity: Activity, val crashlyticsProxy: CrashlyticsProxy
}
}
- override fun onError(i: Int, e: Exception) { crashlyticsProxy.fabricLogE("Purchase", "Consume", e) }
+ override fun onError(i: Int, e: Exception) { crashlyticsProxy.logException(e) }
})
}
}
@@ -158,7 +156,7 @@ class PurchaseHandler(activity: Activity, val crashlyticsProxy: CrashlyticsProxy
}
override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("Purchase", "Consume", e)
+ crashlyticsProxy.logException(e)
}
})
}
@@ -166,7 +164,7 @@ class PurchaseHandler(activity: Activity, val crashlyticsProxy: CrashlyticsProxy
}
override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("Purchase", "getAllPurchases", e)
+ crashlyticsProxy.logException(e)
}
})
}
@@ -180,7 +178,7 @@ class PurchaseHandler(activity: Activity, val crashlyticsProxy: CrashlyticsProxy
override fun onSuccess(o: Any) { /* no-op */ }
override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("PurchaseConsumeException", "Consume", e)
+ crashlyticsProxy.logException(e)
}
})
}
@@ -200,7 +198,7 @@ class PurchaseHandler(activity: Activity, val crashlyticsProxy: CrashlyticsProxy
override fun onSuccess(o: Any) { /* no-op */ }
override fun onError(i: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("PurchaseConsumeException", "Consume", e)
+ crashlyticsProxy.logException(e)
}
})
}
@@ -216,7 +214,7 @@ class PurchaseHandler(activity: Activity, val crashlyticsProxy: CrashlyticsProxy
override fun onSuccess(result: Any) { /* no-op */ }
override fun onError(response: Int, e: Exception) {
- crashlyticsProxy.fabricLogE("PurchaseConsumeException", "Consume", e)
+ crashlyticsProxy.logException(e)
}
})
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.kt
index 25834344d..85c5c2e8a 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/SoundManager.kt
@@ -2,7 +2,6 @@ package com.habitrpg.android.habitica.helpers
import com.habitrpg.android.habitica.HabiticaBaseApplication
import io.reactivex.Maybe
-import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
@@ -48,7 +47,7 @@ class SoundManager {
val soundFiles = ArrayList{ - private final ThreadExecutor threadExecutor; private final PostExecutionThread postExecutionThread; protected UseCase(ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) { - this.threadExecutor = threadExecutor; this.postExecutionThread = postExecutionThread; } - /** - * Builds an {@link rx.Flowable} which will be used when executing the current {@link UseCase}. - */ protected abstract FlowablebuildUseCaseObservable(Q requestValues); - @SuppressWarnings("unchecked") public Flowable observable(Q requestValues) { return this.buildUseCaseObservable(requestValues) .subscribeOn(postExecutionThread.getScheduler()) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.java deleted file mode 100644 index 66a77e762..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.habitrpg.android.habitica.models; - - -import androidx.annotation.Nullable; - -import com.habitrpg.android.habitica.models.user.Outfit; -import com.habitrpg.android.habitica.models.user.Stats; - -/** - * Created by phillip on 29.06.17. - */ - -public interface Avatar { - @Nullable - String getCurrentMount(); - - @Nullable - String getCurrentPet(); - - boolean getSleep(); - - @Nullable - Stats getStats(); - - @Nullable - AvatarPreferences getPreferences(); - - @Nullable - Integer getGemCount(); - - @Nullable - Integer getHourglassCount(); - - @Nullable - Outfit getCostume(); - @Nullable - Outfit getEquipped(); - - boolean hasClass(); - - boolean isValid(); -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.kt new file mode 100644 index 000000000..24e37bd57 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/Avatar.kt @@ -0,0 +1,21 @@ +package com.habitrpg.android.habitica.models + +import com.habitrpg.android.habitica.models.user.Outfit +import com.habitrpg.android.habitica.models.user.Stats + +/** + * Created by phillip on 29.06.17. + */ +interface Avatar { + val currentMount: String? + val currentPet: String? + val sleep: Boolean + val stats: Stats? + val preferences: AvatarPreferences? + val gemCount: Int + val hourglassCount: Int + val costume: Outfit? + val equipped: Outfit? + fun hasClass(): Boolean + fun isValid(): Boolean +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarPreferences.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarPreferences.java deleted file mode 100644 index 36d4a4e6f..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarPreferences.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.habitrpg.android.habitica.models; - -import com.habitrpg.android.habitica.models.user.Hair; - -/** - * Created by phillip on 15.09.17. - */ - -public interface AvatarPreferences { - - String getUserId(); - - Hair getHair(); - - boolean getCostume(); - - boolean getSleep(); - - String getShirt(); - - String getSkin(); - String getSize(); - - String getBackground(); - - String getChair(); - - boolean getDisableClasses(); -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarPreferences.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarPreferences.kt new file mode 100644 index 000000000..e271c00e6 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/AvatarPreferences.kt @@ -0,0 +1,16 @@ +package com.habitrpg.android.habitica.models + +import com.habitrpg.android.habitica.models.user.Hair + +interface AvatarPreferences { + val userId: String? + val hair: Hair? + val costume: Boolean + val sleep: Boolean + val shirt: String? + val skin: String? + val size: String? + val background: String? + val chair: String? + val disableClasses: Boolean +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/HabitRpgClass.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/HabitRpgClass.java deleted file mode 100644 index d7004f308..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/HabitRpgClass.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.habitrpg.android.habitica.models; - -/** - * Created by MagicMicky on 16/03/14. - */ -public enum HabitRpgClass { - rogue, - wizard, - warrior, - healer, - base - -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/PushDevice.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/PushDevice.java deleted file mode 100644 index 7b5c1c1a0..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/PushDevice.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.habitrpg.android.habitica.models; - -import com.google.gson.annotations.Expose; -import com.google.gson.annotations.SerializedName; - -/** - * Created by keithholliday on 7/5/16. - */ -public class PushDevice { - - @SerializedName("regId") - @Expose - private String regId; - - @SerializedName("type") - @Expose - private String type; - - public String getRegId() { - return this.regId; - } - - public void setRegId(String regId) { - this.regId = regId; - } - - public String getType() { - return this.type; - } - - public void setType(String type) { - this.type = type; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/PushDevice.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/PushDevice.kt new file mode 100644 index 000000000..33a32afe9 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/PushDevice.kt @@ -0,0 +1,14 @@ +package com.habitrpg.android.habitica.models + +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +class PushDevice { + @SerializedName("regId") + @Expose + var regId: String? = null + + @SerializedName("type") + @Expose + var type: String? = null +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/Transaction.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/Transaction.kt index 5829d6e93..da0fa66e0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/Transaction.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/Transaction.kt @@ -2,6 +2,5 @@ package com.habitrpg.android.habitica.models class Transaction { var receipt: String? = null - var signature: String? = null } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/WorldState.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/WorldState.kt index cb99a5444..76d268836 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/WorldState.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/WorldState.kt @@ -1,8 +1,8 @@ package com.habitrpg.android.habitica.models -import com.facebook.internal.Mutable import com.habitrpg.android.habitica.models.inventory.QuestProgress import com.habitrpg.android.habitica.models.inventory.QuestRageStrike +import java.util.* class WorldState { @@ -11,4 +11,7 @@ class WorldState { var progress: QuestProgress? = null var rageStrikes: MutableList ? = null + var currentEventKey: String? = null + var currentEventStartDate: Date? = null + var currentEventEndDate: Date? = null } \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Animal.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Animal.java deleted file mode 100644 index 96c1b7f90..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Animal.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -public interface Animal { - - String getKey(); - - void setKey(String key); - - String getText(); - - void setText(String text); - - String getType(); - - void setType(String type); - - String getAnimal(); - - void setAnimal(String animal); - - String getColor(); - - void setColor(String color); - - boolean getPremium(); - - void setPremium(boolean premium); - - Integer getNumberOwned(); - - void setNumberOwned(Integer numberOwned); - - Integer getTotalNumber(); - - void setTotalNumber(Integer totalNumber); -} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Animal.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Animal.kt new file mode 100644 index 000000000..47a7e5255 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Animal.kt @@ -0,0 +1,12 @@ +package com.habitrpg.android.habitica.models.inventory + +interface Animal { + var key: String? + var text: String? + var type: String? + var animal: String + var color: String + var premium: Boolean + var numberOwned: Int + var totalNumber: Int +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/CustomizationSet.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/CustomizationSet.java deleted file mode 100644 index bcb82d9d5..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/CustomizationSet.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -import java.util.List; - -/** - * Created by viirus on 19/01/16. - */ -public class CustomizationSet { - - public String text; - public String identifier; - public Integer price; - public boolean hasPurchasable; - - public List customizations; -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/CustomizationSet.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/CustomizationSet.kt new file mode 100644 index 000000000..aa4ca8b4a --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/CustomizationSet.kt @@ -0,0 +1,9 @@ +package com.habitrpg.android.habitica.models.inventory + +class CustomizationSet { + var text: String? = null + var identifier: String? = null + var price: Int = 0 + var hasPurchasable = false + var customizations: MutableList = mutableListOf() +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Egg.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Egg.java deleted file mode 100644 index 2c41352f2..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Egg.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class Egg extends RealmObject implements Item { - - @PrimaryKey - String key; - String text, notes; - Integer value; - String adjective, mountText; - - Integer stableOwned, stableTotal; - - public String getAdjective() { - return adjective; - } - - public void setAdjective(String adjective) { - this.adjective = adjective; - } - - public String getMountText() { - return mountText; - } - - public void setMountText(String mountText) { - this.mountText = mountText; - } - - public Integer getStableOwned() { - if (stableOwned == null) { - stableOwned = 0; - } - return stableOwned; - } - - public void setStableOwned(Integer stableOwned) { - this.stableOwned = stableOwned; - } - - public Integer getStableTotal() { - return stableTotal; - } - - public void setStableTotal(Integer stableTotal) { - this.stableTotal = stableTotal; - } - - public String getType() { - return "eggs"; - } - - @Override - public String getKey() { - return key; - } - - public String getText() { - return text; - } - - @Override - public Integer getValue() { - return value; - } - - public void setText(String text) { - this.text = text; - } - - public void setValue(Integer value) { - this.value = value; - } - - public String getNotes() { - return notes; - } - - public void setNotes(String notes) { - this.notes = notes; - } - - public void setKey(String key) { - this.key = key; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Egg.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Egg.kt new file mode 100644 index 000000000..d237dbc69 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Egg.kt @@ -0,0 +1,17 @@ +package com.habitrpg.android.habitica.models.inventory + +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class Egg : RealmObject(), Item { + @PrimaryKey + override var key: String = "" + override var text: String = "" + var notes: String? = null + override var value: Int = 0 + var adjective: String? = null + var mountText: String? = null + + override val type: String + get() = "eggs" +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Food.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Food.java deleted file mode 100644 index 936adc6b2..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Food.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class Food extends RealmObject implements Item { - - @PrimaryKey - String key; - String text, notes; - Integer value; - String target, article; - Boolean canDrop; - - public String getTarget() { - return target; - } - - public void setTarget(String target) { - this.target = target; - } - - public String getArticle() { - return article; - } - - public void setArticle(String article) { - this.article = article; - } - - public Boolean getCanDrop() { - return canDrop; - } - - public void setCanDrop(Boolean canDrop) { - this.canDrop = canDrop; - } - - public String getType() { - return "food"; - } - - @Override - public String getKey() { - return key; - } - - @Override - public String getText() { - return text; - } - - @Override - public Integer getValue() { - return value; - } - - public void setText(String text) { - this.text = text; - } - - public String getNotes() { - return notes; - } - - public void setValue(Integer value) { - this.value = value; - } - - public void setNotes(String notes) { - this.notes = notes; - } - - public void setKey(String key) { - this.key = key; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Food.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Food.kt new file mode 100644 index 000000000..4f5f04cd6 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Food.kt @@ -0,0 +1,17 @@ +package com.habitrpg.android.habitica.models.inventory + +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class Food : RealmObject(), Item { + @PrimaryKey + override var key: String = "" + override var text: String = "" + var notes: String? = null + override var value: Int = 0 + var target: String? = null + var article: String? = null + var canDrop: Boolean? = null + override val type: String + get() = "food" +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/HatchingPotion.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/HatchingPotion.java deleted file mode 100644 index 4d42ca4cd..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/HatchingPotion.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class HatchingPotion extends RealmObject implements Item { - - @PrimaryKey - String key; - String text, notes; - Integer value; - Boolean limited, premium; - - public Boolean getLimited() { - return limited; - } - - public void setLimited(Boolean limited) { - this.limited = limited; - } - - public Boolean getPremium() { - return premium; - } - - public void setPremium(Boolean premium) { - this.premium = premium; - } - - @Override - public String getType() { - return "hatchingPotions"; - } - - @Override - public String getKey() { - return key; - } - - public String getText() { - return text; - } - - @Override - public Integer getValue() { - return value; - } - - public void setText(String text) { - this.text = text; - } - - public void setValue(Integer value) { - this.value = value; - } - - public String getNotes() { - return notes; - } - - public void setNotes(String notes) { - this.notes = notes; - } - - public void setKey(String key) { - this.key = key; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/HatchingPotion.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/HatchingPotion.kt new file mode 100644 index 000000000..5257fd502 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/HatchingPotion.kt @@ -0,0 +1,16 @@ +package com.habitrpg.android.habitica.models.inventory + +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class HatchingPotion : RealmObject(), Item { + @PrimaryKey + override var key: String = "" + override var text: String = "" + var notes: String? = null + override var value: Int = 0 + var limited: Boolean? = null + var premium: Boolean? = null + override val type: String + get() = "hatchingPotions" +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Item.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Item.java deleted file mode 100644 index da0f3e08a..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Item.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -import io.realm.RealmModel; - -public interface Item extends RealmModel { - - String getType(); - - String getKey(); - - String getText(); - - Integer getValue(); -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Item.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Item.kt new file mode 100644 index 000000000..0e39a4217 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Item.kt @@ -0,0 +1,10 @@ +package com.habitrpg.android.habitica.models.inventory + +import io.realm.RealmModel + +interface Item : RealmModel { + val type: String + val key: String + val text: String + val value: Int +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Mount.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Mount.java deleted file mode 100644 index 1fd23de3c..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Mount.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -import io.realm.RealmObject; -import io.realm.annotations.Ignore; -import io.realm.annotations.PrimaryKey; - -public class Mount extends RealmObject implements Animal { - - @PrimaryKey - String key; - String animal, color, text, type; - boolean premium; - - @Ignore - private Integer numberOwned; - - @Ignore - private Integer totalNumber; - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - @Override - public String getText() { - return text; - } - - @Override - public void setText(String text) { - this.text = text; - } - - @Override - public String getType() { - return type; - } - - @Override - public void setType(String type) { - this.type = type; - } - - public String getAnimal() { - if (animal == null) { - return key.split("-")[0]; - } - return animal; - } - - public void setAnimal(String animal) { - this.animal = animal; - } - - public String getColor() { - if (color == null) { - return key.split("-")[1]; - } - return color; - } - - public void setColor(String color) { - this.color = color; - } - - public boolean getPremium() { - return premium; - } - - public void setPremium(boolean premium) { - this.premium = premium; - } - - public Integer getNumberOwned() { - if (numberOwned == null) { - return 0; - } - return numberOwned; - } - - public void setNumberOwned(Integer numberOwned) { - this.numberOwned = numberOwned; - } - - public Integer getTotalNumber() { - if (totalNumber == null) { - return 0; - } - return totalNumber; - } - - public void setTotalNumber(Integer totalNumber) { - this.totalNumber = totalNumber; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Mount.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Mount.kt new file mode 100644 index 000000000..3e4386536 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Mount.kt @@ -0,0 +1,31 @@ +package com.habitrpg.android.habitica.models.inventory + +import io.realm.RealmObject +import io.realm.annotations.Ignore +import io.realm.annotations.PrimaryKey + +open class Mount : RealmObject(), Animal { + @PrimaryKey + override var key: String? = null + override var animal: String = "" + get() { + return if (field.isBlank()) { + key?.split("-")?.toTypedArray()?.get(0) ?: "" + } else field + } + override var color: String = "" + get() { + return if (field.isBlank()) { + key?.split("-")?.toTypedArray()?.get(1) ?: "" + } else field + } + override var text: String? = null + override var type: String? = null + override var premium = false + + + @Ignore + override var numberOwned: Int = 0 + @Ignore + override var totalNumber: Int = 0 +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Pet.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Pet.java deleted file mode 100644 index 642c2c1fc..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Pet.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -import io.realm.RealmObject; -import io.realm.annotations.Ignore; -import io.realm.annotations.PrimaryKey; - -public class Pet extends RealmObject implements Animal{ - - @PrimaryKey - String key; - String animal, color, text, type; - boolean premium; - - @Ignore - private Integer numberOwned; - - @Ignore - private Integer totalNumber; - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - @Override - public String getText() { - return text; - } - - - @Override - public void setText(String text) { - this.text = text; - } - - @Override - public String getType() { - return type; - } - - @Override - public void setType(String type) { - this.type = type; - } - - public String getAnimal() { - if (animal == null) { - return getKey().split("-")[0]; - } - return animal; - } - - public void setAnimal(String animal) { - this.animal = animal; - } - - public String getColor() { - if (color == null) { - return getKey().split("-")[1]; - } - return color; - } - - public void setColor(String color) { - this.color = color; - } - - public boolean getPremium() { - return premium; - } - - public void setPremium(boolean premium) { - this.premium = premium; - } - - public Integer getNumberOwned() { - if (numberOwned == null) { - return 0; - } - return numberOwned; - } - - public void setNumberOwned(Integer numberOwned) { - this.numberOwned = numberOwned; - } - - public Integer getTotalNumber() { - if (totalNumber == null) { - return 0; - } - - return totalNumber; - } - - public void setTotalNumber(Integer totalNumber) { - this.totalNumber = totalNumber; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Pet.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Pet.kt new file mode 100644 index 000000000..7d2d69566 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/Pet.kt @@ -0,0 +1,30 @@ +package com.habitrpg.android.habitica.models.inventory + +import io.realm.RealmObject +import io.realm.annotations.Ignore +import io.realm.annotations.PrimaryKey + +open class Pet : RealmObject(), Animal { + @PrimaryKey + override var key: String? = null + override var animal: String = "" + get() { + return if (field.isBlank()) { + key?.split("-")?.toTypedArray()?.get(0) ?: "" + } else field + } + override var color: String = "" + get() { + return if (field.isBlank()) { + key?.split("-")?.toTypedArray()?.get(1) ?: "" + } else field + } + override var text: String? = null + override var type: String? = null + override var premium = false + + @Ignore + override var numberOwned: Int = 0 + @Ignore + override var totalNumber: Int = 0 +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestColors.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestColors.kt index ac7a25e30..12394fa6d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestColors.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestColors.kt @@ -17,19 +17,19 @@ open class QuestColors : RealmObject() { var light: String? = null var extralight: String? = null - var darkColor: Int = 0 + val darkColor: Int get() { return Color.parseColor(dark) } - var mediumColor: Int = 0 + val mediumColor: Int get() { return Color.parseColor(medium) } - var lightColor: Int = 0 + val lightColor: Int get() { return Color.parseColor(light) } - var extraLightColor: Int = 0 + val extraLightColor: Int get() { return Color.parseColor(extralight) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestContent.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestContent.kt index a5d84d7a6..b2996fe41 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestContent.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestContent.kt @@ -7,17 +7,17 @@ import io.realm.annotations.PrimaryKey open class QuestContent : RealmObject(), Item { @PrimaryKey - internal var key: String = "" + override var key: String = "" set(value) { field = value drop?.key = value colors?.key = value boss?.key = value } - internal var text: String = "" + override var text: String = "" var notes: String = "" var completion: String = "" - internal var value: Int = 0 + override var value: Int = 0 var previous: String? = null var lvl: Int = 0 var isCanBuy: Boolean = false @@ -49,33 +49,8 @@ open class QuestContent : RealmObject(), Item { val isBossQuest: Boolean get() = this.boss != null - override fun getType(): String { - return "quests" - } - - override fun getKey(): String { - return key - } - - override fun getText(): String { - return text - } - - override fun getValue(): Int? { - return value - } - - fun setText(text: String) { - this.text = text - } - - fun setValue(value: Int) { - this.value = value - } - - fun setKey(key: String) { - this.key = key - } + override val type: String + get() = "quests" fun getCollectWithKey(key: String): QuestCollect? { for (collect in this.collect ?: emptyList ()) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDropItem.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDropItem.java deleted file mode 100644 index f50a5155f..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDropItem.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -/** - * Created by phillip on 25.07.17. - */ - -public class QuestDropItem extends RealmObject { - - @PrimaryKey - private String combinedKey; - private String questKey; - private String key; - private String type; - private String text; - private boolean onlyOwner; - private int count; - - public QuestDropItem() { - super(); - } - - public String getCombinedKey() { - return combinedKey; - } - - public void setCombinedKey(String combinedKey) { - this.combinedKey = combinedKey; - } - - public String getQuestKey() { - return questKey; - } - - public void setQuestKey(String questKey) { - this.questKey = questKey; - combinedKey = questKey+key; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - combinedKey = questKey+key; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } - - public int getCount() { - return count; - } - - public void setCount(int count) { - this.count = count; - } - - public String getImageName() { - if ("quests".equals(type)) { - return "inventory_quest_scroll_"+key; - } else if ("eggs".equals(type)) { - return "Pet_Egg_" + getKey(); - } else - if ("food".equals(type)) { - return "Pet_Food_" + getKey(); - } else - if ("hatchingPotions".equals(type)) { - return "Pet_HatchingPotion_" + getKey(); - } - return "shop_"+key; - } - - public boolean isOnlyOwner() { - return onlyOwner; - } - - public void setOnlyOwner(boolean onlyOwner) { - this.onlyOwner = onlyOwner; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDropItem.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDropItem.kt new file mode 100644 index 000000000..0efd92ee9 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDropItem.kt @@ -0,0 +1,35 @@ +package com.habitrpg.android.habitica.models.inventory + +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +/** + * Created by phillip on 25.07.17. + */ +open class QuestDropItem : RealmObject() { + @PrimaryKey + var combinedKey: String? = null + var questKey: String? = null + set(value) { + field = value + combinedKey = value + key + } + var key: String = "" + set(value) { + field = value + combinedKey = questKey + value + } + var type: String? = null + var text: String? = null + var isOnlyOwner = false + var count = 0 + + val imageName: String + get() = when (type) { + "quests" -> "inventory_quest_scroll_$key" + "eggs" -> "Pet_Egg_$key" + "food" -> "Pet_Food_$key" + "hatchingPotions" -> "Pet_HatchingPotion_$key" + else -> "shop_$key" + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDrops.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDrops.java deleted file mode 100644 index f76dc7c18..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDrops.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.habitrpg.android.habitica.models.inventory; - -import io.realm.RealmList; -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -/** - * Created by phillip on 25.07.17. - */ - -public class QuestDrops extends RealmObject { - - @PrimaryKey - private String key; - public int gp; - public int exp; - public String unlock; - private RealmList items; - - public QuestDrops() { - super(); - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - - if (items != null) { - for (QuestDropItem item : items) { - item.setQuestKey(key); - } - } - } - - - public RealmList getItems() { - return items; - } - - public void setItems(RealmList items) { - this.items = items; - - if (items != null) { - for (QuestDropItem item : items) { - item.setQuestKey(key); - } - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDrops.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDrops.kt new file mode 100644 index 000000000..e4b5ae7ea --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/QuestDrops.kt @@ -0,0 +1,25 @@ +package com.habitrpg.android.habitica.models.inventory + +import io.realm.RealmList +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +/** + * Created by phillip on 25.07.17. + */ +open class QuestDrops : RealmObject() { + @PrimaryKey + var key: String? = null + set(value) { + field = value + items?.forEach { it.questKey = key } + } + var gp = 0 + var exp = 0 + var unlock: String? = null + var items: RealmList ? = null + set(value) { + field = value + items?.forEach { it.questKey = key } + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/SpecialItem.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/SpecialItem.kt index dcee52123..bcaf614a8 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/SpecialItem.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/SpecialItem.kt @@ -7,30 +7,16 @@ import io.realm.RealmObject import io.realm.annotations.PrimaryKey open class SpecialItem : RealmObject(), Item { + override val type: String + get() = "special" @PrimaryKey - internal var key: String = "" - internal var text: String = "" + override var key: String = "" + override var text: String = "" internal var notes: String = "" - internal var value: Int? = null + override var value: Int = 0 var isMysteryItem: Boolean = false - override fun getType(): String { - return "special" - } - - override fun getKey(): String { - return key - } - - override fun getText(): String { - return text - } - - override fun getValue(): Int? { - return value - } - companion object { fun makeMysteryItem(context: Context): SpecialItem { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/Member.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/Member.kt index 4a80be93c..f59028103 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/Member.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/Member.kt @@ -10,7 +10,6 @@ import io.realm.annotations.PrimaryKey open class Member : RealmObject(), Avatar { - @PrimaryKey @SerializedName("_id") var id: String? = null @@ -27,7 +26,7 @@ open class Member : RealmObject(), Avatar { this.inbox?.userId = subID } if (preferences != null && preferences?.isManaged != true) { - preferences?.setUserId(subID) + preferences?.userId = subID } if (this.profile != null && this.profile?.isManaged != true) { this.profile?.userId = subID @@ -45,7 +44,13 @@ open class Member : RealmObject(), Avatar { this.authentication?.userId = subID } } - private var stats: Stats? = null + override var stats: Stats? = null + set(value) { + field = value + if (value != null && this.id != null && !value.isManaged) { + field?.userId = this.id + } + } var inbox: Inbox? = null set(inbox) { field = inbox @@ -53,7 +58,17 @@ open class Member : RealmObject(), Avatar { inbox.userId = this.id } } - private var preferences: MemberPreferences? = null + override var preferences: MemberPreferences? = null + set(value) { + field = value + if (value != null && this.id != null && !value.isManaged) { + field?.userId = this.id + } + } + override val gemCount: Int + get() = 0 + override val hourglassCount: Int + get() = 0 var profile: Profile? = null set(profile) { field = profile @@ -96,11 +111,23 @@ open class Member : RealmObject(), Avatar { items.userId = this.id } } - private var costume: Outfit? = null - private var equipped: Outfit? = null + override var costume: Outfit? = null + set(value) { + field = value + if (value != null && this.id != null) { + field?.userId = this.id + "costume" + } + } + override var equipped: Outfit? = null + set(value) { + field = value + if (value != null && this.id != null) { + field?.userId = this.id + "equipped" + } + } - private var currentMount: String? = null - private var currentPet: String? = null + override var currentMount: String? = null + override var currentPet: String? = null var participatesInQuest: Boolean? = null var loginIncentives: Int = 0 @@ -120,79 +147,10 @@ open class Member : RealmObject(), Avatar { val formattedUsername: String? get() = if (username != null) "@$username" else null - override fun getPreferences(): MemberPreferences? { - return preferences - } - - fun setPreferences(preferences: MemberPreferences?) { - this.preferences = preferences - if (preferences != null && this.id != null && !preferences.isManaged) { - preferences.setUserId(this.id ?: "") - } - } - - override fun getStats(): Stats? { - return stats - } - - fun setStats(stats: Stats?) { - this.stats = stats - if (stats != null && this.id != null && !stats.isManaged) { - stats.userId = this.id - } - } - - override fun getGemCount(): Int? { - return 0 - } - - override fun getHourglassCount(): Int? { - return 0 - } - - override fun getCostume(): Outfit? { - return costume - } - - fun setCostume(costume: Outfit?) { - this.costume = costume - if (costume != null && this.id != null) { - costume.userId = this.id + "costume" - } - } - - override fun getEquipped(): Outfit? { - return equipped - } - override fun hasClass(): Boolean { return preferences?.disableClasses == false && stats?.habitClass?.isNotEmpty() == true } - fun setEquipped(equipped: Outfit?) { - this.equipped = equipped - if (equipped != null && this.id != null) { - equipped.userId = this.id + "equipped" - } - } - - override fun getCurrentMount(): String? { - return currentMount - } - - fun setCurrentMount(currentMount: String) { - this.currentMount = currentMount - } - - override fun getCurrentPet(): String? { - return currentPet - } - - fun setCurrentPet(currentPet: String) { - this.currentPet = currentPet - } - - override fun getSleep(): Boolean { - return getPreferences()?.sleep ?: false - } + override val sleep: Boolean + get() = preferences?.sleep ?: false } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/MemberPreferences.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/MemberPreferences.kt index 011d2a9c8..d764ba74e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/MemberPreferences.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/members/MemberPreferences.kt @@ -10,104 +10,31 @@ import io.realm.annotations.PrimaryKey open class MemberPreferences : RealmObject(), AvatarPreferences { @PrimaryKey - private var userId: String? = null - - private var hair: Hair? = null - private var costume: Boolean = false - private var disableClasses: Boolean = false - private var sleep: Boolean = false - private var shirt: String? = null - private var skin: String? = null - private var size: String? = null - private var background: String? = null - private var chair: String? = null - - fun setUserId(userId: String) { - this.userId = userId - if (hair != null && !hair!!.isManaged) { - hair!!.userId = userId + override var userId: String? = null + set(value) { + field = value + if (hair?.isManaged != true) { + hair?.userId = userId } } - override fun getUserId(): String? { - return userId - } - - override fun getHair(): Hair? { - return hair - } - - fun setHair(hair: Hair) { - this.hair = hair - } - - override fun getCostume(): Boolean { - return costume - } - - fun setCostume(costume: Boolean) { - this.costume = costume - } - - override fun getDisableClasses(): Boolean { - return disableClasses - } - - fun setDisableClasses(disableClasses: Boolean) { - this.disableClasses = disableClasses - } - - override fun getSleep(): Boolean { - return sleep - } - - fun setSleep(sleep: Boolean) { - this.sleep = sleep - } - - override fun getShirt(): String? { - return shirt - } - - fun setShirt(shirt: String) { - this.shirt = shirt - } - - override fun getSkin(): String? { - return skin - } - - fun setSkin(skin: String) { - this.skin = skin - } - - override fun getSize(): String? { - return size - } - - fun setSize(size: String) { - this.size = size - } - - override fun getBackground(): String? { - return background - } - - fun setBackground(background: String) { - this.background = background - } - - override fun getChair(): String? { - return if (chair != null && chair != "none") { - if (chair!!.length > 5 && chair!!.substring(0, 6) != "chair_") { - chair + override var hair: Hair? = null + override var costume: Boolean = false + override var disableClasses: Boolean = false + override var sleep: Boolean = false + override var shirt: String? = null + override var skin: String? = null + override var size: String? = null + override var background: String? = null + override var chair: String? = null + get() { + return if (field != null && field != "none") { + if (field!!.length > 5 && field?.substring(0, 6) != "chair_") { + field } else { - "chair_" + chair!! + "chair_$field" } } else null } - fun setChair(chair: String) { - this.chair = chair - } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/Reward.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/Reward.java deleted file mode 100644 index e44e08293..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/Reward.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.habitrpg.android.habitica.models.notifications; - -/** - * Created by krh12 on 12/1/2016. - */ - -public class Reward { - public String key; -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/Reward.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/Reward.kt new file mode 100644 index 000000000..165d46669 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/notifications/Reward.kt @@ -0,0 +1,5 @@ +package com.habitrpg.android.habitica.models.notifications + +class Reward { + var key: String? = null +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/FallExtraGemsHabiticaPromotion.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/FallExtraGemsHabiticaPromotion.kt new file mode 100644 index 000000000..83b28dabe --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/FallExtraGemsHabiticaPromotion.kt @@ -0,0 +1,142 @@ +package com.habitrpg.android.habitica.models.promotions + +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.graphics.drawable.ShapeDrawable +import android.view.View +import androidx.core.content.ContextCompat +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.databinding.FragmentGemPurchaseBinding +import com.habitrpg.android.habitica.databinding.PurchaseGemViewBinding +import com.habitrpg.android.habitica.extensions.DateUtils +import com.habitrpg.android.habitica.helpers.MainNavigationController +import com.habitrpg.android.habitica.ui.fragments.PromoInfoFragment +import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper +import com.habitrpg.android.habitica.ui.views.promo.PromoMenuView +import java.text.SimpleDateFormat +import java.util.* + +class FallExtraGemsHabiticaPromotion(startDate: Date?, endDate: Date?) : HabiticaPromotion() { + override val identifier: String + get() = "fall_extra_gems" + override val promoType: PromoType + get() = PromoType.GEMS_AMOUNT + override val startDate: Date = startDate ?: DateUtils.createDate(2020, 8, 22) + override val endDate: Date = endDate ?: DateUtils.createDate(2020, 8, 30) + + override fun pillBackgroundDrawable(context: Context): Drawable { + return ContextCompat.getDrawable(context, R.drawable.fall_promo_pill_bg) ?: ShapeDrawable() + } + + override fun backgroundColor(context: Context): Int { + return ContextCompat.getColor(context, R.color.gray_10) + } + + override fun promoBackgroundDrawable(context: Context): Drawable { + return ContextCompat.getDrawable(context, R.drawable.layout_rounded_bg_gray_10) + ?: ShapeDrawable() + } + + override fun buttonDrawable(context: Context): Drawable { + return ContextCompat.getDrawable(context, R.drawable.fall_promo_button_bg) + ?: ShapeDrawable() + } + + override fun configurePromoMenuView(view: PromoMenuView) { + val context = view.context + view.setBackgroundColor(backgroundColor(context)) + view.setTitleImage(ContextCompat.getDrawable(context, R.drawable.fall_promo_title)) + view.setTitleText(null) + view.setSubtitleImage(ContextCompat.getDrawable(context, R.drawable.fall_promo_menu_description)) + view.setSubtitleText(null) + + view.setDecoration( + ContextCompat.getDrawable(context, R.drawable.fall_promo_menu_left), + ContextCompat.getDrawable(context, R.drawable.fall_promo_menu_right) + ) + + view.binding.button.backgroundTintList = ContextCompat.getColorStateList(context, R.color.gray_1) + view.binding.button.setText(R.string.learn_more) + view.binding.button.setTextColor(ContextCompat.getColor(context, R.color.white)) + view.binding.button.setOnClickListener { + menuOnNavigation(context) + } + } + + override fun menuOnNavigation(context: Context) { + MainNavigationController.navigate(R.id.promoInfoFragment) + } + + override fun configurePurchaseBanner(binding: FragmentGemPurchaseBinding) { + val context = binding.root.context + binding.promoBanner.visibility = View.VISIBLE + binding.promoBanner.background = promoBackgroundDrawable(context) + binding.promoBannerLeftImage.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.fall_promo_banner_left)) + binding.promoBannerRightImage.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.fall_promo_banner_right)) + binding.promoBannerTitleImage.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.fall_promo_title)) + val formatter = SimpleDateFormat("MMM d", Locale.getDefault()) + binding.promoBannerDurationView.text = context.getString(R.string.x_to_y, + formatter.format(startDate), + formatter.format(endDate)) + binding.promoBannerDurationView.setTextColor(Color.parseColor("#FEE2B6")) + } + + override fun configureGemView(binding: PurchaseGemViewBinding, regularAmount: Int) { + val context = binding.root.context + binding.root.background = promoBackgroundDrawable(context) + binding.purchaseButton.background = buttonDrawable(context) + val colors = listOf( + ContextCompat.getColor(context, R.color.red_10), + ContextCompat.getColor(context, R.color.blue_50), + ContextCompat.getColor(context, R.color.green_50), + ContextCompat.getColor(context, R.color.brand_300) + ).shuffled() + val drawable = BitmapDrawable(context.resources, + HabiticaIconsHelper.imageOfFallGemPromoBG( + colors[0], + colors[1], + colors[2], + colors[3] + )) + binding.amountBackgroundLeft.background = drawable + binding.amountBackgroundRight.background = drawable + binding.gemAmount.setTextColor(Color.parseColor("#FEE2B6")) + binding.gemsTextView.setTextColor(Color.parseColor("#FEE2B6")) + binding.footerTextView.visibility = View.VISIBLE + binding.footerTextView.text = context.getString(R.string.usually_x_gems, regularAmount) + binding.gemAmount.text = when (regularAmount) { + 4 -> "5" + 21 -> "30" + 42 -> "60" + 84 -> "125" + else -> regularAmount.toString() + } + } + + override fun configureInfoFragment(fragment: PromoInfoFragment) { + val context = fragment.context ?: return + fragment.binding?.promoBanner?.background = promoBackgroundDrawable(context) + fragment.binding?.promoBannerLeftImage?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.fall_promo_info_left)) + fragment.binding?.promoBannerRightImage?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.fall_promo_info_right)) + fragment.binding?.promoBannerTitleImage?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.fall_promo_title)) + fragment.binding?.promoBannerSubtitleView?.setText(R.string.limited_event) + fragment.binding?.promoBannerDurationView?.setTextColor(Color.parseColor("#FEE2B6")) + val formatter = SimpleDateFormat("MMM d", Locale.getDefault()) + fragment.binding?.promoBannerDurationView?.text = context.getString(R.string.x_to_y, + formatter.format(startDate), + formatter.format(endDate)) + fragment.binding?.promoBannerDurationView?.setTextColor(ContextCompat.getColor(context, R.color.white)) + fragment.binding?.promptText?.setText(R.string.fall_promo_info_prompt) + fragment.binding?.promptText?.setTextColor(Color.parseColor("#F78E2F")) + fragment.binding?.promptButton?.background = buttonDrawable(context) + fragment.binding?.promptButton?.setText(R.string.view_gem_bundles) + fragment.binding?.promptButton?.setTextColor(ContextCompat.getColor(context, R.color.white)) + fragment.binding?.promptButton?.setOnClickListener { MainNavigationController.navigate(R.id.gemPurchaseActivity) } + + fragment.binding?.instructionDescriptionView?.text = context.getString(R.string.fall_promo_info_instructions, formatter.format(startDate), formatter.format(endDate)) + val limitationsFormatter = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.LONG, SimpleDateFormat.LONG) + fragment.binding?.limitationsDescriptionView?.text = context.getString(R.string.gems_promo_info_limitations, limitationsFormatter.format(startDate), limitationsFormatter.format(endDate)) + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/HabiticaPromotion.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/HabiticaPromotion.kt new file mode 100644 index 000000000..bc8e23e76 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/HabiticaPromotion.kt @@ -0,0 +1,46 @@ +package com.habitrpg.android.habitica.models.promotions + +import android.content.Context +import android.graphics.drawable.Drawable +import com.habitrpg.android.habitica.databinding.FragmentGemPurchaseBinding +import com.habitrpg.android.habitica.databinding.PurchaseGemViewBinding +import com.habitrpg.android.habitica.ui.fragments.PromoInfoFragment +import com.habitrpg.android.habitica.ui.views.promo.PromoMenuView +import java.util.* + +enum class PromoType { + GEMS_AMOUNT, + GEMS_PRICE, + SUBSCRIPTION +} + +abstract class HabiticaPromotion { + abstract val identifier: String + abstract val promoType: PromoType + + abstract val startDate: Date + abstract val endDate: Date + + abstract fun pillBackgroundDrawable(context: Context): Drawable + abstract fun backgroundColor(context: Context): Int + abstract fun promoBackgroundDrawable(context: Context): Drawable + + abstract fun buttonDrawable(context: Context): Drawable + + abstract fun configurePromoMenuView(view: PromoMenuView) + abstract fun menuOnNavigation(context: Context) + + abstract fun configurePurchaseBanner(binding: FragmentGemPurchaseBinding) + + abstract fun configureGemView(binding: PurchaseGemViewBinding, regularAmount: Int) + abstract fun configureInfoFragment(fragment: PromoInfoFragment) +} + +fun getHabiticaPromotionFromKey(key: String, startDate: Date?, endDate: Date?): HabiticaPromotion? { + return when (key) { + "fall_extra_gems", "fall2020", "testFall2020" -> FallExtraGemsHabiticaPromotion(startDate, endDate) + "spooky_extra_gems", "fall2020SecondPromo", "spooky2020" -> SpookyExtraGemsHabiticaPromotion(startDate, endDate) + else -> null + } +} + diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/SpookyExtraGemsHabiticaPromo.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/SpookyExtraGemsHabiticaPromo.kt new file mode 100644 index 000000000..29b846256 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/promotions/SpookyExtraGemsHabiticaPromo.kt @@ -0,0 +1,130 @@ +package com.habitrpg.android.habitica.models.promotions + +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.graphics.drawable.ShapeDrawable +import android.view.View +import androidx.core.content.ContextCompat +import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.databinding.FragmentGemPurchaseBinding +import com.habitrpg.android.habitica.databinding.PurchaseGemViewBinding +import com.habitrpg.android.habitica.extensions.DateUtils +import com.habitrpg.android.habitica.helpers.MainNavigationController +import com.habitrpg.android.habitica.ui.fragments.PromoInfoFragment +import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper +import com.habitrpg.android.habitica.ui.views.promo.PromoMenuView +import java.text.SimpleDateFormat +import java.util.* + +class SpookyExtraGemsHabiticaPromotion(startDate: Date?, endDate: Date?) : HabiticaPromotion() { + override val identifier: String + get() = "spooky_extra_gems" + override val promoType: PromoType + get() = PromoType.GEMS_AMOUNT + override val startDate: Date = startDate ?: DateUtils.createDate(2020, 9, 29) + override val endDate: Date = endDate ?: DateUtils.createDate(2020, 10, 2) + + override fun pillBackgroundDrawable(context: Context): Drawable { + return ContextCompat.getDrawable(context, R.drawable.spooky_promo_pill_bg) ?: ShapeDrawable() + } + + override fun backgroundColor(context: Context): Int { + return ContextCompat.getColor(context, R.color.gray_10) + } + + override fun promoBackgroundDrawable(context: Context): Drawable { + return ContextCompat.getDrawable(context, R.drawable.layout_rounded_bg_gray_10) + ?: ShapeDrawable() + } + + override fun buttonDrawable(context: Context): Drawable { + return ContextCompat.getDrawable(context, R.drawable.spooky_promo_button_bg) + ?: ShapeDrawable() + } + + override fun configurePromoMenuView(view: PromoMenuView) { + val context = view.context + view.setBackgroundColor(backgroundColor(context)) + view.setTitleImage(ContextCompat.getDrawable(context, R.drawable.spooky_promo_title)) + view.setTitleText(null) + view.setSubtitleImage(ContextCompat.getDrawable(context, R.drawable.spooky_promo_menu_description)) + view.setSubtitleText(null) + + view.setDecoration( + ContextCompat.getDrawable(context, R.drawable.spooky_promo_menu_left), + ContextCompat.getDrawable(context, R.drawable.spooky_promo_menu_right) + ) + + view.binding.button.backgroundTintList = ContextCompat.getColorStateList(context, R.color.gray_1) + view.binding.button.setText(R.string.learn_more) + view.binding.button.setTextColor(ContextCompat.getColor(context, R.color.white)) + view.binding.button.setOnClickListener { + menuOnNavigation(context) + } + } + + override fun menuOnNavigation(context: Context) { + MainNavigationController.navigate(R.id.promoInfoFragment) + } + + override fun configurePurchaseBanner(binding: FragmentGemPurchaseBinding) { + val context = binding.root.context + binding.promoBanner.visibility = View.VISIBLE + binding.promoBanner.background = promoBackgroundDrawable(context) + binding.promoBannerLeftImage.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.spooky_promo_banner_left)) + binding.promoBannerRightImage.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.spooky_promo_banner_right)) + binding.promoBannerTitleImage.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.spooky_promo_title)) + val formatter = SimpleDateFormat("MMM d", Locale.getDefault()) + binding.promoBannerDurationView.text = context.getString(R.string.x_to_y, + formatter.format(startDate), + formatter.format(endDate)) + binding.promoBannerDurationView.setTextColor(ContextCompat.getColor(context, R.color.white)) + } + + override fun configureGemView(binding: PurchaseGemViewBinding, regularAmount: Int) { + val context = binding.root.context + binding.root.background = promoBackgroundDrawable(context) + binding.purchaseButton.background = buttonDrawable(context) + val drawable = BitmapDrawable(context.resources, + HabiticaIconsHelper.imageOfSpookyGemPromoBG()) + binding.amountBackgroundLeft.background = drawable + binding.amountBackgroundRight.background = drawable + binding.gemAmount.setTextColor(Color.parseColor("#FEE2B6")) + binding.gemsTextView.setTextColor(Color.parseColor("#FEE2B6")) + binding.footerTextView.visibility = View.VISIBLE + binding.footerTextView.text = context.getString(R.string.usually_x_gems, regularAmount) + binding.gemAmount.text = when (regularAmount) { + 4 -> "5" + 21 -> "30" + 42 -> "60" + 84 -> "125" + else -> regularAmount.toString() + } + } + + override fun configureInfoFragment(fragment: PromoInfoFragment) { + val context = fragment.context ?: return + fragment.binding?.promoBanner?.background = promoBackgroundDrawable(context) + fragment.binding?.promoBannerLeftImage?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.spooky_promo_info_left)) + fragment.binding?.promoBannerRightImage?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.spooky_promo_info_right)) + fragment.binding?.promoBannerTitleImage?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.spooky_promo_title)) + fragment.binding?.promoBannerSubtitleView?.setText(R.string.limited_event) + fragment.binding?.promoBannerDurationView?.setTextColor(ContextCompat.getColor(context, R.color.white)) + val formatter = SimpleDateFormat("MMM d", Locale.getDefault()) + fragment.binding?.promoBannerDurationView?.text = context.getString(R.string.x_to_y, + formatter.format(startDate), + formatter.format(endDate)) + fragment.binding?.promoBannerDurationView?.setTextColor(ContextCompat.getColor(context, R.color.white)) + fragment.binding?.promptText?.setText(R.string.spooky_promo_info_prompt) + fragment.binding?.promptText?.setTextColor(ContextCompat.getColor(context, R.color.orange_50)) + fragment.binding?.promptButton?.background = buttonDrawable(context) + fragment.binding?.promptButton?.setText(R.string.view_gem_bundles) + fragment.binding?.promptButton?.setTextColor(ContextCompat.getColor(context, R.color.white)) + fragment.binding?.promptButton?.setOnClickListener { MainNavigationController.navigate(R.id.gemPurchaseActivity) } + + fragment.binding?.instructionDescriptionView?.text = context.getString(R.string.spooky_promo_info_instructions, formatter.format(startDate), formatter.format(endDate)) + val limitationsFormatter = SimpleDateFormat.getDateTimeInstance() + fragment.binding?.limitationsDescriptionView?.text = context.getString(R.string.gems_promo_info_limitations, limitationsFormatter.format(startDate), limitationsFormatter.format(endDate)) } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/shops/ShopItem.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/shops/ShopItem.kt index 5e7fa29f4..a6c52fd8c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/shops/ShopItem.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/shops/ShopItem.kt @@ -69,13 +69,11 @@ open class ShopItem : RealmObject() { get() = "pets" == purchaseType || "mounts" == purchaseType val canPurchaseBulk: Boolean - get() = "eggs" == purchaseType || "hatchingPotions" == purchaseType || "food" == purchaseType + get() = "eggs" == purchaseType || "hatchingPotions" == purchaseType || "food" == purchaseType || "gems" == purchaseType fun canAfford(user: User?, quantity: Int): Boolean = when(currency) { "gold" -> (value * quantity) <= user?.stats?.gp ?: 0.0 - "gems" -> (value * quantity) <= user?.gemCount?.toDouble() ?: 0.0 - "hourglasses" -> (value * quantity) <= user?.hourglassCount?.toDouble() ?: 0.0 - else -> false + else -> true } override fun equals(other: Any?): Boolean { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/FindUsernameResult.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/FindUsernameResult.kt index 89c187510..fe6387683 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/FindUsernameResult.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/FindUsernameResult.kt @@ -4,7 +4,6 @@ import com.google.gson.annotations.SerializedName import com.habitrpg.android.habitica.models.user.Authentication import com.habitrpg.android.habitica.models.user.ContributorInfo import com.habitrpg.android.habitica.models.user.Profile -import io.realm.annotations.PrimaryKey class FindUsernameResult { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/UserStyles.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/UserStyles.kt index cd6b32c81..a6e246422 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/UserStyles.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/social/UserStyles.kt @@ -1,7 +1,6 @@ package com.habitrpg.android.habitica.models.social import com.habitrpg.android.habitica.models.Avatar -import com.habitrpg.android.habitica.models.AvatarPreferences import com.habitrpg.android.habitica.models.user.Items import com.habitrpg.android.habitica.models.user.Outfit import com.habitrpg.android.habitica.models.user.Preferences @@ -18,47 +17,32 @@ open class UserStyles : RealmObject(), Avatar { preferences?.userId = id items?.userId = id } - override fun getCurrentMount(): String? { - return items?.currentMount - } - override fun getCurrentPet(): String? { - return items?.currentPet - } + override val currentMount: String? + get() = items?.currentMount - override fun getSleep(): Boolean { - return false - } + override val currentPet: String? + get() = items?.currentPet - override fun getStats(): Stats? { - return stats - } + override val sleep: Boolean + get() = false - override fun getPreferences(): AvatarPreferences? { - return preferences - } + override val gemCount: Int + get() = 0 + override val hourglassCount: Int + get() = 0 - override fun getGemCount(): Int { - return 0 - } + override val costume: Outfit? + get() = items?.gear?.costume - override fun getHourglassCount(): Int { - return 0 - } - - override fun getCostume(): Outfit? { - return items?.gear?.costume - } - - override fun getEquipped(): Outfit? { - return items?.gear?.equipped - } + override val equipped: Outfit? + get() = items?.gear?.equipped override fun hasClass(): Boolean { return false } - private var stats: Stats? = null - private var preferences: Preferences? = null + override var stats: Stats? = null + override var preferences: Preferences? = null private var items: Items? = null } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt index 60af9bf85..7cdf310a2 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt @@ -9,7 +9,6 @@ import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.models.Tag import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.ui.helpers.MarkdownParser -import io.reactivex.functions.Consumer import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.Ignore @@ -123,7 +122,7 @@ open class Task : RealmObject, Parcelable { this.value < -20 -> return R.color.maroon_50 this.value < -10 -> return R.color.red_50 this.value < -1 -> return R.color.orange_50 - this.value < 1 -> return R.color.yellow_50 + this.value < 1 -> return R.color.yellow_10 this.value < 5 -> return R.color.green_50 this.value < 10 -> return R.color.teal_50 else -> R.color.blue_50 @@ -136,7 +135,7 @@ open class Task : RealmObject, Parcelable { this.value < -20 -> return R.color.maroon_10 this.value < -10 -> return R.color.red_10 this.value < -1 -> return R.color.orange_10 - this.value < 1 -> return R.color.yellow_10 + this.value < 1 -> return R.color.yellow_5 this.value < 5 -> return R.color.green_10 this.value < 10 -> return R.color.teal_10 else -> R.color.blue_10 @@ -199,7 +198,7 @@ open class Task : RealmObject, Parcelable { return this.parsedText ?: "" } - MarkdownParser.parseMarkdownAsync(this.text, Consumer { parsedText -> + MarkdownParser.parseMarkdownAsync(this.text, { parsedText -> this.parsedText = parsedText callback(parsedText) }) @@ -213,7 +212,7 @@ open class Task : RealmObject, Parcelable { } if (notes?.isNotEmpty() == true) { - MarkdownParser.parseMarkdownAsync(notes, Consumer { parsedText -> + MarkdownParser.parseMarkdownAsync(notes, { parsedText -> parsedNotes = parsedText callback(parsedText) }) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskList.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskList.java deleted file mode 100644 index 9cb9c6ffa..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskList.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.habitrpg.android.habitica.models.tasks; - -import java.util.Map; - -public class TaskList { - - public Map tasks; - -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskList.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskList.kt new file mode 100644 index 000000000..2b754b324 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskList.kt @@ -0,0 +1,5 @@ +package com.habitrpg.android.habitica.models.tasks + +class TaskList { + var tasks: MutableMap = mutableMapOf() +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskTag.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskTag.java deleted file mode 100644 index 979cda714..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskTag.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.habitrpg.android.habitica.models.tasks; - - -import com.habitrpg.android.habitica.models.Tag; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -/** - * Created by viirus on 08/08/15. - */ - -public class TaskTag extends RealmObject { - - public Tag tag; - public Task task; - @PrimaryKey - String id; - private String tagId = ""; - private String taskId = ""; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public Tag getTag() { - return tag; - } - - public void setTag(Tag tag) { - this.tag = tag; - tagId = tag.getId(); - updatePrimaryKey(); - } - - public Task getTask() { - return task; - } - - public void setTask(Task task) { - this.task = task; - - taskId = task.getId(); - updatePrimaryKey(); - } - - private void updatePrimaryKey() { - this.id = taskId + "_" + tagId; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskTag.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskTag.kt new file mode 100644 index 000000000..cc8e02636 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskTag.kt @@ -0,0 +1,29 @@ +package com.habitrpg.android.habitica.models.tasks + +import com.habitrpg.android.habitica.models.Tag +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class TaskTag : RealmObject() { + var tag: Tag? = null + set(value) { + field = value + tagId = tag?.id ?: "" + updatePrimaryKey() + } + var task: Task? = null + set(value) { + field = value + taskId = task?.id ?: "" + updatePrimaryKey() + } + + @PrimaryKey + var id: String? = null + private var tagId = "" + private var taskId: String? = "" + + private fun updatePrimaryKey() { + id = taskId + "_" + tagId + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TasksOrder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TasksOrder.java deleted file mode 100644 index 227566ab8..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TasksOrder.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.habitrpg.android.habitica.models.tasks; - -import java.util.List; - -public class TasksOrder { - - List habits; - List dailys; - List todos; - List rewards; - - public List getHabits() { - return habits; - } - - public void setHabits(List habits) { - this.habits = habits; - } - - public List getDailys() { - return dailys; - } - - public void setDailys(List dailys) { - this.dailys = dailys; - } - - public List getTodos() { - return todos; - } - - public void setTodos(List todos) { - this.todos = todos; - } - - public List getRewards() { - return rewards; - } - - public void setRewards(List rewards) { - this.rewards = rewards; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TasksOrder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TasksOrder.kt new file mode 100644 index 000000000..e345c1ccc --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TasksOrder.kt @@ -0,0 +1,8 @@ +package com.habitrpg.android.habitica.models.tasks + +class TasksOrder { + var habits: List = listOf() + var dailys: List = listOf() + var todos: List = listOf() + var rewards: List = listOf() +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Buffs.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Buffs.java deleted file mode 100644 index 21898ac0b..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Buffs.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.habitrpg.android.habitica.models.user; - -import com.google.gson.annotations.SerializedName; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class Buffs extends RealmObject { - - @PrimaryKey - private String userId; - - public Float con, str, per; - @SerializedName("int") - public Float _int; private Boolean snowball; - private Boolean streaks; - private Boolean seafoam; - private Boolean spookySparkles; - private Boolean shinySeed; - - public Buffs() { - this(false, false); - } - - public Buffs(Boolean snowball, Boolean streaks) { - this.snowball = snowball; - this.streaks = streaks; - } - - public Boolean getSnowball() { - return snowball != null ? snowball : Boolean.FALSE; - } - - public void setSnowball(Boolean snowball) { - this.snowball = snowball; - } - - public Boolean getSeafoam() { - return seafoam != null ? seafoam : Boolean.FALSE; - } - - public void setSeafoam(Boolean seafoam) { - this.seafoam = seafoam; - } - - public Boolean getSpookySparkles() { - return spookySparkles != null ? spookySparkles : Boolean.FALSE; - } - - public void setSpookySparkles(Boolean spookySparkles) { - this.spookySparkles = spookySparkles; - } - - public Boolean getShinySeed() { - return shinySeed != null ? shinySeed : Boolean.FALSE; - } - - public void setShinySeed(Boolean shinySeed) { - this.shinySeed = shinySeed; - } - - public Boolean getStreaks() { - return streaks != null ? streaks : Boolean.FALSE; - } - - public void setStreaks(Boolean streaks) { - this.streaks = streaks; - } - - public void merge(Buffs stats) { - if (stats == null) { - return; - } - this.con = stats.con != null ? stats.con : this.con; - this.str = stats.str != null ? stats.str : this.str; - this.per = stats.per != null ? stats.per : this.per; - this._int = stats._int != null ? stats._int : this._int; - this.snowball = stats.snowball != null ? stats.snowball : this.snowball; - this.streaks = stats.streaks != null ? stats.streaks : this.streaks; - this.seafoam = stats.seafoam != null ? stats.seafoam : this.seafoam; - this.shinySeed = stats.shinySeed != null ? stats.shinySeed : this.shinySeed; - this.spookySparkles = stats.spookySparkles != null ? stats.spookySparkles : this.spookySparkles; - } - - public Float getStr() { - return str; - } - - public Float get_int() { - return _int; - } - - public Float getCon() { - return con; - } - - public Float getPer() { - return per; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Buffs.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Buffs.kt new file mode 100644 index 000000000..d366f518c --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Buffs.kt @@ -0,0 +1,42 @@ +package com.habitrpg.android.habitica.models.user + +import com.google.gson.annotations.SerializedName +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class Buffs : RealmObject() { + @PrimaryKey + var userId: String? = null + var con: Float? = null + var str: Float? = null + var per: Float? = null + + @SerializedName("int") + var _int: Float? = null + var seafoam: Boolean? = null + get() { return field ?: false } + var spookySparkles: Boolean? = null + get() { return field ?: false } + var shinySeed: Boolean? = null + get() { return field ?: false } + var snowball: Boolean? = null + get() { return field ?: false } + var streaks: Boolean? = null + get() { return field ?: false } + + + fun merge(stats: Buffs?) { + if (stats == null) { + return + } + con = if (stats.con != null) stats.con else con + str = if (stats.str != null) stats.str else str + per = if (stats.per != null) stats.per else per + _int = if (stats._int != null) stats._int else _int + snowball = if (stats.snowball != null) stats.snowball else snowball + streaks = if (stats.streaks != null) stats.streaks else streaks + seafoam = if (stats.seafoam != null) stats.seafoam else seafoam + shinySeed = if (stats.shinySeed != null) stats.shinySeed else shinySeed + spookySparkles = if (stats.spookySparkles != null) stats.spookySparkles else spookySparkles + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/ContributorInfo.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/ContributorInfo.java deleted file mode 100644 index 1eb1589a5..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/ContributorInfo.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.habitrpg.android.habitica.models.user; - -import android.util.SparseArray; -import android.util.SparseIntArray; - -import com.habitrpg.android.habitica.R; - -import java.util.HashMap; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class ContributorInfo extends RealmObject { - - public static final SparseIntArray CONTRIBUTOR_COLOR_DICT; - - static { - CONTRIBUTOR_COLOR_DICT = new SparseIntArray(); - CONTRIBUTOR_COLOR_DICT.put(0, R.color.contributor_0); - CONTRIBUTOR_COLOR_DICT.put(1, R.color.contributor_1); - CONTRIBUTOR_COLOR_DICT.put(2, R.color.contributor_2); - CONTRIBUTOR_COLOR_DICT.put(3, R.color.contributor_3); - CONTRIBUTOR_COLOR_DICT.put(4, R.color.contributor_4); - CONTRIBUTOR_COLOR_DICT.put(5, R.color.contributor_5); - CONTRIBUTOR_COLOR_DICT.put(6, R.color.contributor_6); - CONTRIBUTOR_COLOR_DICT.put(7, R.color.contributor_7); - CONTRIBUTOR_COLOR_DICT.put(8, R.color.contributor_mod); - CONTRIBUTOR_COLOR_DICT.put(9, R.color.contributor_staff); - } - - @PrimaryKey - private String userId; - - public User user; - private boolean admin; - private String contributions; - private int level; - private String text; - - public Boolean getAdmin() { - return this.admin; - } - - public void setAdmin(Boolean admin) { - this.admin = admin; - } - - public String getContributions() { - return this.contributions; - } - - public void setContributions(String contributions) { - this.contributions = contributions; - } - - public int getLevel() { - return this.level; - } - - public void setLevel(int level) { - this.level = level; - } - - public String getText() { - return this.text; - } - - public void setText(String text) { - this.text = text; - } - - public int getContributorColor() { - int rColor = android.R.color.black; - - - if (CONTRIBUTOR_COLOR_DICT.get(this.level, -1) > 0) { - rColor = CONTRIBUTOR_COLOR_DICT.get(this.level); - } - - return rColor; - } - - public int getContributorForegroundColor() { - return android.R.color.white; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/ContributorInfo.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/ContributorInfo.kt new file mode 100644 index 000000000..a3aa155b7 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/ContributorInfo.kt @@ -0,0 +1,42 @@ +package com.habitrpg.android.habitica.models.user + +import io.realm.RealmObject +import android.util.SparseIntArray +import com.habitrpg.android.habitica.models.user.ContributorInfo +import com.habitrpg.android.habitica.R +import io.realm.annotations.PrimaryKey + +open class ContributorInfo : RealmObject() { + companion object { + val CONTRIBUTOR_COLOR_DICT: SparseIntArray = SparseIntArray() + + init { + CONTRIBUTOR_COLOR_DICT.put(0, R.color.contributor_0) + CONTRIBUTOR_COLOR_DICT.put(1, R.color.contributor_1) + CONTRIBUTOR_COLOR_DICT.put(2, R.color.contributor_2) + CONTRIBUTOR_COLOR_DICT.put(3, R.color.contributor_3) + CONTRIBUTOR_COLOR_DICT.put(4, R.color.contributor_4) + CONTRIBUTOR_COLOR_DICT.put(5, R.color.contributor_5) + CONTRIBUTOR_COLOR_DICT.put(6, R.color.contributor_6) + CONTRIBUTOR_COLOR_DICT.put(7, R.color.contributor_7) + CONTRIBUTOR_COLOR_DICT.put(8, R.color.contributor_mod) + CONTRIBUTOR_COLOR_DICT.put(9, R.color.contributor_staff) + } + } + + @PrimaryKey + var userId: String? = null + var user: User? = null + var admin = false + var contributions: String? = null + var level = 0 + var text: String? = null + val contributorColor: Int + get() { + var rColor = R.color.text_primary + if (CONTRIBUTOR_COLOR_DICT[level, -1] > 0) { + rColor = CONTRIBUTOR_COLOR_DICT[level] + } + return rColor + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.java deleted file mode 100644 index 402f66d67..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.habitrpg.android.habitica.models.user; - -import com.habitrpg.android.habitica.models.TutorialStep; - -import java.util.List; - -import io.realm.RealmList; -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class Flags extends RealmObject { - - @PrimaryKey - private String userId; - - RealmList tutorial; - private boolean showTour; - private boolean dropsEnabled; - private boolean itemsEnabled; - private boolean newStuff; - private boolean classSelected; - private boolean rebirthEnabled; - private boolean welcomed; - private boolean armoireEnabled; - private boolean armoireOpened; - private boolean armoireEmpty; - private boolean communityGuidelinesAccepted; - private boolean verifiedUsername; - private boolean warnedLowHealth; - - public List getTutorial() { - return tutorial; - } - - public void setTutorial(RealmList tutorial) { - this.tutorial = tutorial; - } - - public boolean getShowTour() { - return showTour; - } - - public void setShowTour(boolean showTour) { - this.showTour = showTour; - } - - public boolean getDropsEnabled() { - return dropsEnabled; - } - - public void setDropsEnabled(boolean dropsEnabled) { - this.dropsEnabled = dropsEnabled; - } - - public boolean getItemsEnabled() { - return itemsEnabled; - } - - public void setItemsEnabled(boolean itemsEnabled) { - this.itemsEnabled = itemsEnabled; - } - - public boolean getNewStuff() { - return newStuff; - } - - public void setNewStuff(boolean newStuff) { - this.newStuff = newStuff; - } - - public boolean getClassSelected() { - return classSelected; - } - - public void setClassSelected(boolean classSelected) { - this.classSelected = classSelected; - } - - public boolean getRebirthEnabled() { - return rebirthEnabled; - } - - public void setRebirthEnabled(boolean rebirthEnabled) { - this.rebirthEnabled = rebirthEnabled; - } - - public boolean getWelcomed() { - return welcomed; - } - - public void setWelcomed(boolean welcomed) { - this.welcomed = welcomed; - } - - public boolean getArmoireEnabled() { - return armoireEnabled; - } - - public void setArmoireEnabled(boolean armoireEnabled) { - this.armoireEnabled = armoireEnabled; - } - - public boolean getArmoireOpened() { - return armoireOpened; - } - - public void setArmoireOpened(boolean armoireOpened) { - this.armoireOpened = armoireOpened; - } - - public boolean getArmoireEmpty() { - return armoireEmpty; - } - - public void setArmoireEmpty(boolean armoireEmpty) { - this.armoireEmpty = armoireEmpty; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public boolean isCommunityGuidelinesAccepted() { - return communityGuidelinesAccepted; - } - - public void setCommunityGuidelinesAccepted(boolean communityGuidelinesAccepted) { - this.communityGuidelinesAccepted = communityGuidelinesAccepted; - } - - public boolean isVerifiedUsername() { - return verifiedUsername; - } - - public void setVerifiedUsername(boolean verifiedUsername) { - this.verifiedUsername = verifiedUsername; - } - - public boolean isWarnedLowHealth() { - return warnedLowHealth; - } - - public void setWarnedLowHealth(boolean warnedLowHealth) { - this.warnedLowHealth = warnedLowHealth; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.kt new file mode 100644 index 000000000..735569bda --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Flags.kt @@ -0,0 +1,25 @@ +package com.habitrpg.android.habitica.models.user + +import com.habitrpg.android.habitica.models.TutorialStep +import io.realm.RealmList +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class Flags : RealmObject() { + @PrimaryKey + var userId: String? = null + var tutorial: RealmList ? = null + var showTour = false + var dropsEnabled = false + var itemsEnabled = false + var newStuff = false + var classSelected = false + var rebirthEnabled = false + var welcomed = false + var armoireEnabled = false + var armoireOpened = false + var armoireEmpty = false + var communityGuidelinesAccepted = false + var verifiedUsername = false + var isWarnedLowHealth = false +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Inbox.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Inbox.kt index 7184c1645..d07a896e1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Inbox.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Inbox.kt @@ -1,9 +1,8 @@ package com.habitrpg.android.habitica.models.user +import io.realm.RealmList import io.realm.RealmObject -import io.realm.annotations.Ignore import io.realm.annotations.PrimaryKey -import java.util.* open class Inbox : RealmObject() { @@ -11,26 +10,7 @@ open class Inbox : RealmObject() { var userId: String? = null internal var user: User? = null - /** - * @return The optOut - */ - /** - * @param optOut The optOut - */ var optOut: Boolean = false - /** - * @return The blocks - */ - /** - * @param blocks The blocks - */ - @Ignore - var blocks: List = ArrayList() - /** - * @return The newMessages - */ - /** - * @param newMessages The newMessages - */ + var blocks: RealmList = RealmList() var newMessages: Int = 0 } \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Preferences.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Preferences.kt index 8d450cfc4..caf02668f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Preferences.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Preferences.kt @@ -11,23 +11,41 @@ import java.util.* open class Preferences : RealmObject(), AvatarPreferences { @PrimaryKey - private var userId: String? = null + override var userId: String? = null + set(value) { + field = value + if (hair?.isManaged == false) { + hair?.userId = value + } + if (suppressModals?.isManaged == false) { + suppressModals?.userId = value + } + } - private var hair: Hair? = null + override var hair: Hair? = null var suppressModals: SuppressedModals? = null - private var costume: Boolean = false + override var costume: Boolean = false @SerializedName("disableClasses") - var isDisableClasses: Boolean = false + override var disableClasses: Boolean = false @SerializedName("sleep") - var isSleep: Boolean = false + override var sleep: Boolean = false var dailyDueDefaultView: Boolean = false var automaticAllocation: Boolean = false var allocationMode: String? = null - private var shirt: String? = null - private var skin: String? = null - private var size: String? = null - private var background: String? = null - private var chair: String? = null + override var shirt: String? = null + override var skin: String? = null + override var size: String? = null + override var background: String? = null + override var chair: String? = null + get() { + return if (field != null && field != "none") { + if (field?.contains("chair_") == true) { + field + } else { + "chair_" + field!! + } + } else null + } var language: String? = null var sound: String? = null var dayStart: Int = 0 @@ -37,90 +55,6 @@ open class Preferences : RealmObject(), AvatarPreferences { var emailNotifications: EmailNotificationsPreference? = null var autoEquip: Boolean = true - override fun getBackground(): String? { - return background - } - - fun setBackground(background: String) { - this.background = background - } - - override fun getCostume(): Boolean { - return costume - } - - fun setCostume(costume: Boolean) { - this.costume = costume - } - - override fun getDisableClasses(): Boolean { - return isDisableClasses - } - - override fun getSleep(): Boolean { - return isSleep - } - - override fun getShirt(): String? { - return shirt - } - - fun setShirt(shirt: String) { - this.shirt = shirt - } - - override fun getSkin(): String? { - return skin - } - - fun setSkin(skin: String) { - this.skin = skin - } - - override fun getSize(): String? { - return size - } - - fun setSize(size: String) { - this.size = size - } - - override fun getHair(): Hair? { - return hair - } - - fun setHair(hair: Hair) { - this.hair = hair - } - - override fun getChair(): String? { - return if (chair != null && chair != "none") { - if (chair?.contains("chair_") == true) { - chair - } else { - "chair_" + chair!! - } - } else null - } - - fun setChair(chair: String) { - this.chair = chair - } - - override fun getUserId(): String? { - return userId - } - - fun setUserId(userId: String?) { - this.userId = userId - if (hair?.isManaged == false) { - hair?.userId = userId - } - if (suppressModals?.isManaged == false) { - suppressModals?.userId = userId - } - } - fun hasTaskBasedAllocation(): Boolean { return allocationMode?.toLowerCase(Locale.ROOT) == "taskbased" && automaticAllocation } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Purchases.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Purchases.java deleted file mode 100644 index 89f35152e..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Purchases.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.habitrpg.android.habitica.models.user; - -import java.util.List; - -import io.realm.RealmList; -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class Purchases extends RealmObject { - - @PrimaryKey - private String userId; - - public RealmList customizations; - User user; - private SubscriptionPlan plan; - - public List getCustomizations() { - return customizations; - } - - public void setCustomizations(RealmList customizations) { - this.customizations = customizations; - } - - public SubscriptionPlan getPlan() { - return plan; - } - - public void setPlan(SubscriptionPlan plan) { - this.plan = plan; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Purchases.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Purchases.kt new file mode 100644 index 000000000..37f8f0f3c --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Purchases.kt @@ -0,0 +1,14 @@ +package com.habitrpg.android.habitica.models.user + +import io.realm.RealmList +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class Purchases : RealmObject() { + @PrimaryKey + var userId: String? = null + @JvmField + var customizations: RealmList ? = null + var user: User? = null + var plan: SubscriptionPlan? = null +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.kt index 1b413f3a7..b04867e22 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Stats.kt @@ -3,7 +3,6 @@ package com.habitrpg.android.habitica.models.user import android.content.Context import com.google.gson.annotations.SerializedName import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.models.HabitRpgClass import io.realm.RealmObject import io.realm.annotations.PrimaryKey @@ -102,10 +101,6 @@ open class Stats : RealmObject() { this.maxMP = if (stats.maxMP != null) stats.maxMP else this.maxMP } - fun setHabitClass(habitRpgClass: HabitRpgClass) { - habitClass = habitRpgClass.toString() - } - companion object { const val STRENGTH = "str" const val INTELLIGENCE = "int" diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanConsecutive.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanConsecutive.java deleted file mode 100644 index 2bade8afe..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanConsecutive.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.habitrpg.android.habitica.models.user; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class SubscriptionPlanConsecutive extends RealmObject { - - @PrimaryKey - private String customerId; - - SubscriptionPlan subscriptionPlan; - private int trinkets; - private int gemCapExtra; - private int offset; - private int count; - - public int getTrinkets() { - return trinkets; - } - - public void setTrinkets(int trinkets) { - this.trinkets = trinkets; - } - - public int getGemCapExtra() { - return gemCapExtra; - } - - public void setGemCapExtra(int gemCapExtra) { - this.gemCapExtra = gemCapExtra; - } - - public int getOffset() { - return offset; - } - - public void setOffset(int offset) { - this.offset = offset; - } - - public int getCount() { - return count; - } - - public void setCount(int count) { - this.count = count; - } - - public String getCustomerId() { - return customerId; - } - - public void setCustomerId(String customerId) { - this.customerId = customerId; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanConsecutive.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanConsecutive.kt new file mode 100644 index 000000000..05541cd6d --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlanConsecutive.kt @@ -0,0 +1,14 @@ +package com.habitrpg.android.habitica.models.user + +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class SubscriptionPlanConsecutive : RealmObject() { + @PrimaryKey + var customerId: String? = null + var subscriptionPlan: SubscriptionPlan? = null + var trinkets = 0 + var gemCapExtra = 0 + var offset = 0 + var count = 0 +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SuppressedModals.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SuppressedModals.java deleted file mode 100644 index 77b40827b..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SuppressedModals.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.habitrpg.android.habitica.models.user; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class SuppressedModals extends RealmObject { - - @PrimaryKey - private String userId; - - Preferences preferences; - private Boolean streak, raisePet, hatchPet, levelUp; - - public Boolean getStreak() { - return streak; - } - - public void setStreak(Boolean streak) { - this.streak = streak; - } - - public Boolean getRaisePet() { - return raisePet; - } - - public void setRaisePet(Boolean raisePet) { - this.raisePet = raisePet; - } - - public Boolean getHatchPet() { - return hatchPet; - } - - public void setHatchPet(Boolean hatchPet) { - this.hatchPet = hatchPet; - } - - public Boolean getLevelUp() { - return levelUp; - } - - public void setLevelUp(Boolean levelUp) { - this.levelUp = levelUp; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SuppressedModals.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SuppressedModals.kt new file mode 100644 index 000000000..ed69c1996 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SuppressedModals.kt @@ -0,0 +1,14 @@ +package com.habitrpg.android.habitica.models.user + +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class SuppressedModals : RealmObject() { + @PrimaryKey + var userId: String? = null + var preferences: Preferences? = null + var streak: Boolean? = null + var raisePet: Boolean? = null + var hatchPet: Boolean? = null + var levelUp: Boolean? = null +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Training.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Training.java deleted file mode 100644 index 1e7154f48..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Training.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.habitrpg.android.habitica.models.user; - -import com.google.gson.annotations.SerializedName; - -import io.realm.RealmObject; -import io.realm.annotations.PrimaryKey; - -public class Training extends RealmObject { - - @PrimaryKey - private String userId; - - Stats stats; - public Float con, str, per; - @SerializedName("int") - public Float _int; - - public Float getCon() { - return con != null ? con : Float.valueOf(0); - } - - public void setCon(Float con) { - this.con = con; - } - - public Float getStr() { - return str != null ? str : Float.valueOf(0); - } - - public void setStr(Float str) { - this.str = str; - } - - public Float getPer() { - return per != null ? per : Float.valueOf(0); - } - - public void setPer(Float per) { - this.per = per; - } - - public Float get_int() { - return _int != null ? _int : Float.valueOf(0); - } - - public void set_int(Float _int) { - this._int = _int; - } - - public void merge(Training stats) { - if (stats == null) { - return; - } - this.con = stats.con != null ? stats.con : this.con; - this.str = stats.str != null ? stats.str : this.str; - this.per = stats.per != null ? stats.per : this.per; - this._int = stats._int != null ? stats._int : this._int; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } -} - diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Training.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Training.kt new file mode 100644 index 000000000..94819837d --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Training.kt @@ -0,0 +1,27 @@ +package com.habitrpg.android.habitica.models.user + +import com.google.gson.annotations.SerializedName +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class Training : RealmObject() { + @PrimaryKey + var userId: String? = null + var stats: Stats? = null + var con: Float = 0f + var str: Float = 0f + var per: Float = 0f + + @SerializedName("int") + var _int: Float = 0f + + fun merge(stats: Training?) { + if (stats == null) { + return + } + con = stats.con + str = stats.str + per = stats.per + _int = stats._int + } +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.kt index 2fd86f3dc..0fb8a326b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/User.kt @@ -1,6 +1,7 @@ package com.habitrpg.android.habitica.models.user import com.google.gson.annotations.SerializedName +import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.models.* import com.habitrpg.android.habitica.models.invitations.Invitations import com.habitrpg.android.habitica.models.social.ChallengeMembership @@ -53,7 +54,7 @@ open class User : RealmObject(), Avatar, VersionedObject { for (test in abTests ?: emptyList ()) { test.userID = id } - for (achievement in achievements ?: emptyList ()) { + for (achievement in achievements) { achievement.userId = id } } @@ -62,7 +63,13 @@ open class User : RealmObject(), Avatar, VersionedObject { override var versionNumber: Int = 0 var balance: Double = 0.toDouble() - private var stats: Stats? = null + override var stats: Stats? = null + set(value) { + field = value + if (value != null && this.id != null && !value.isManaged) { + field?.userId = this.id + } + } var inbox: Inbox? = null set(inbox) { field = inbox @@ -70,7 +77,13 @@ open class User : RealmObject(), Avatar, VersionedObject { inbox.userId = this.id } } - private var preferences: Preferences? = null + override var preferences: Preferences? = null + set(value) { + field = value + if (value != null && this.id != null && !value.isManaged) { + field?.userId = this.id + } + } var profile: Profile? = null set(profile) { field = profile @@ -167,65 +180,35 @@ open class User : RealmObject(), Avatar, VersionedObject { get() = this.items?.mounts?.size ?: 0 val contributorColor: Int - get() = this.contributor?.contributorColor ?: android.R.color.black + get() = this.contributor?.contributorColor ?: R.color.text_primary val username: String? get() = authentication?.localAuthentication?.username val formattedUsername: String? get() = if (username != null) "@$username" else null - override fun getPreferences(): Preferences? { - return preferences - } + override val gemCount: Int + get() = (this.balance * 4).toInt() - fun setPreferences(preferences: Preferences?) { - this.preferences = preferences - if (preferences != null && this.id != null && !preferences.isManaged) { - preferences.userId = this.id - } - } + override val hourglassCount: Int + get() = purchased?.plan?.consecutive?.trinkets ?: 0 - override fun getStats(): Stats? { - return stats - } + override val costume: Outfit? + get() = items?.gear?.costume - fun setStats(stats: Stats?) { - this.stats = stats - if (stats != null && this.id != null && !stats.isManaged) { - stats.userId = this.id - } - } - - override fun getGemCount(): Int { - return (this.balance * 4).toInt() - } - - override fun getHourglassCount(): Int { - return purchased?.plan?.consecutive?.trinkets ?: 0 - } - - override fun getCostume(): Outfit? { - return items?.gear?.costume - } - - override fun getEquipped(): Outfit? { - return items?.gear?.equipped - } + override val equipped: Outfit? + get() = items?.gear?.equipped override fun hasClass(): Boolean { return preferences?.disableClasses != true && flags?.classSelected == true && stats?.habitClass?.isNotEmpty() == true } - override fun getCurrentMount(): String? { - return items?.currentMount ?: "" - } + override val currentMount: String? + get() = items?.currentMount ?: "" + override val currentPet: String? + get() = items?.currentPet ?: "" - override fun getCurrentPet(): String? { - return items?.currentPet ?: "" - } - - override fun getSleep(): Boolean { - return preferences?.sleep ?: false - } + override val sleep: Boolean + get() = preferences?.sleep ?: false fun hasParty(): Boolean { return this.party?.id?.length ?: 0 > 0 diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserRepositoryModule.java b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserRepositoryModule.java index cb43e1e52..6f03d6ccd 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserRepositoryModule.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/UserRepositoryModule.java @@ -112,7 +112,7 @@ public class UserRepositoryModule { @Provides InventoryLocalRepository providesInventoryLocalRepository(Realm realm, Context context) { - return new RealmInventoryLocalRepository(realm, context); + return new RealmInventoryLocalRepository(realm); } @Provides diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/CrashlyticsProxy.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/CrashlyticsProxy.kt index 442b84a25..ce9b158da 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/CrashlyticsProxy.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/CrashlyticsProxy.kt @@ -1,20 +1,10 @@ package com.habitrpg.android.habitica.proxy -import android.content.Context - interface CrashlyticsProxy { - fun init(context: Context) - fun logException(t: Throwable) - fun setString(key: String, value: String) - fun setUserIdentifier(identifier: String) - fun setUserName(name: String) - - fun fabricLogE(s1: String, s2: String, e: Exception) - fun log(msg: String) } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/implementation/EmptyCrashlyticsProxy.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/implementation/EmptyCrashlyticsProxy.kt index e10609e4a..468729888 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/implementation/EmptyCrashlyticsProxy.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/proxy/implementation/EmptyCrashlyticsProxy.kt @@ -1,35 +1,18 @@ package com.habitrpg.android.habitica.proxy.implementation -import android.content.Context - import com.habitrpg.android.habitica.proxy.CrashlyticsProxy class EmptyCrashlyticsProxy : CrashlyticsProxy { - override fun init(context: Context) { - //pass - } override fun logException(e: Throwable) { //pass } - override fun setString(key: String, value: String) { - //pass - } - override fun setUserIdentifier(identifier: String) { //pass } - override fun setUserName(name: String) { - //pass - } - - override fun fabricLogE(s1: String, s2: String, e: Exception) { - //pass - } - override fun log(msg: String) { //pass } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/LocalNotificationActionReceiver.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/LocalNotificationActionReceiver.kt index de9d5b28c..49941a2ce 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/LocalNotificationActionReceiver.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/LocalNotificationActionReceiver.kt @@ -14,7 +14,6 @@ import com.habitrpg.android.habitica.data.TaskRepository import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.user.User -import io.reactivex.functions.Consumer import javax.inject.Inject class LocalNotificationActionReceiver : BroadcastReceiver() { @@ -48,34 +47,34 @@ class LocalNotificationActionReceiver : BroadcastReceiver() { when (action) { context?.getString(R.string.accept_party_invite) -> { groupID?.let { - socialRepository.joinGroup(it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + socialRepository.joinGroup(it).subscribe({ }, RxErrorHandler.handleEmptyError()) } } context?.getString(R.string.reject_party_invite) -> { groupID?.let { - socialRepository.rejectGroupInvite(it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + socialRepository.rejectGroupInvite(it).subscribe({ }, RxErrorHandler.handleEmptyError()) } } context?.getString(R.string.accept_quest_invite) -> { - socialRepository.acceptQuest(user).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + socialRepository.acceptQuest(user).subscribe({ }, RxErrorHandler.handleEmptyError()) } context?.getString(R.string.reject_quest_invite) -> { - socialRepository.rejectQuest(user).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + socialRepository.rejectQuest(user).subscribe({ }, RxErrorHandler.handleEmptyError()) } context?.getString(R.string.accept_guild_invite) -> { groupID?.let { - socialRepository.joinGroup(it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + socialRepository.joinGroup(it).subscribe({ }, RxErrorHandler.handleEmptyError()) } } context?.getString(R.string.reject_guild_invite) -> { groupID?.let { - socialRepository.rejectGroupInvite(it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + socialRepository.rejectGroupInvite(it).subscribe({ }, RxErrorHandler.handleEmptyError()) } } context?.getString(R.string.group_message_reply) -> { groupID?.let { getMessageText(context?.getString(R.string.group_message_reply))?.let { message -> - socialRepository.postGroupChat(it, message).subscribe(Consumer { + socialRepository.postGroupChat(it, message).subscribe({ context?.let { c -> NotificationManagerCompat.from(c).cancel(it.hashCode()) } }, RxErrorHandler.handleEmptyError()) } @@ -84,14 +83,14 @@ class LocalNotificationActionReceiver : BroadcastReceiver() { context?.getString(R.string.inbox_message_reply) -> { senderID?.let { getMessageText(context?.getString(R.string.inbox_message_reply))?.let { message -> - socialRepository.postPrivateMessage(it, message).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + socialRepository.postPrivateMessage(it, message).subscribe({ }, RxErrorHandler.handleEmptyError()) } } } context?.getString(R.string.complete_task_action) -> { intent?.extras?.getString("taskID")?.let { - taskRepository.taskChecked(null, it, up = true, force = false) { _ -> - }.subscribe(Consumer {}, RxErrorHandler.handleEmptyError()) + taskRepository.taskChecked(null, it, up = true, force = false) { + }.subscribe({}, RxErrorHandler.handleEmptyError()) } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/NotificationPublisher.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/NotificationPublisher.kt index 0ddeb1960..ed4dd1334 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/NotificationPublisher.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/NotificationPublisher.kt @@ -22,7 +22,6 @@ import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.activities.MainActivity import io.reactivex.functions.BiFunction -import io.reactivex.functions.Consumer import io.realm.RealmResults import java.util.* import javax.inject.Inject @@ -65,7 +64,7 @@ class NotificationPublisher : BroadcastReceiver() { if (checkDailies) { taskRepository.getTasks(Task.TYPE_DAILY).firstElement().zipWith(userRepository.getUser().firstElement(), BiFunction , User, Pair , User>> { tasks, user -> return@BiFunction Pair(tasks, user) - }).subscribe(Consumer { pair -> + }).subscribe({ pair -> var showNotifications = false for (task in pair.first) { if (task?.checkIfDue() == true) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt index 396edfe86..ab6963a6a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarView.kt @@ -15,6 +15,7 @@ import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder import com.facebook.drawee.view.DraweeHolder import com.facebook.drawee.view.MultiDraweeHolder import com.facebook.imagepipeline.image.ImageInfo +import com.habitrpg.android.habitica.BuildConfig import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.helpers.AppConfigManager import com.habitrpg.android.habitica.models.Avatar @@ -42,7 +43,6 @@ class AvatarView : View { private var avatarBitmap: Bitmap? = null private var avatarCanvas: Canvas? = null private var currentLayers: Map ? = null - var enableNewSnowman = false private val layerMap: Map get() { @@ -56,8 +56,9 @@ class AvatarView : View { private val avatarImage: Bitmap? get() { - assert(avatar != null) - assert(avatarRectF != null) + if (BuildConfig.DEBUG && (avatar == null || avatarRectF == null)) { + error("Assertion failed") + } val canvasRect = Rect() avatarRectF?.round(canvasRect) avatarBitmap = Bitmap.createBitmap(canvasRect.width(), canvasRect.height(), Bitmap.Config.ARGB_8888) @@ -189,7 +190,7 @@ class AvatarView : View { } private fun substituteOrReturn(substitutions: Map ?, name: String): String { - for (key in substitutions?.keys ?: arrayListOf ()) { + for (key in substitutions?.keys ?: arrayListOf()) { if (name.contains(key)) { return substitutions?.get(key) ?: name } @@ -201,7 +202,7 @@ class AvatarView : View { private fun getAvatarLayerMap(avatar: Avatar, substitutions: Map >): EnumMap { val layerMap = EnumMap (LayerType::class.java) - if (!avatar.isValid) { + if (!avatar.isValid()) { return layerMap } @@ -448,7 +449,7 @@ class AvatarView : View { initAvatarRectMatrix() // draw only when user is set - if (avatar?.isValid != true) return + if (avatar?.isValid() != true) return // request image layers if not yet processed if (multiDraweeHolder.size() == 0) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt index 8186be945..0789c334a 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/AvatarWithBarsViewModel.kt @@ -18,7 +18,6 @@ import com.habitrpg.android.habitica.models.Avatar import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper -import com.habitrpg.android.habitica.ui.views.ValueBar import io.reactivex.disposables.Disposable import org.greenrobot.eventbus.Subscribe import java.util.* @@ -66,7 +65,7 @@ class AvatarWithBarsViewModel(private val context: Context, private val binding: if (!user.hasClass()) { setUserLevel(context, binding.lvlTv, stats.lvl) } else { - setUserLevelWithClass(context, binding.lvlTv, stats.lvl, capitalize(userClass), stats.habitClass) + setUserLevelWithClass(context, binding.lvlTv, stats.lvl, userClass.capitalize(Locale.getDefault()), stats.habitClass) } setHpBarData(stats.hp?.toFloat() ?: 0.toFloat(), stats.maxHealth ?: 0) @@ -119,23 +118,7 @@ class AvatarWithBarsViewModel(private val context: Context, private val binding: binding.currencyView.gems = gems.toDouble() } - fun valueBarLabelsToBlack() { - binding.hpBar.setLightBackground(true) - binding.xpBar.setLightBackground(true) - binding.mpBar.setLightBackground(true) - } - companion object { - fun setHpBarData(valueBar: ValueBar, stats: Stats) { - var maxHP = stats.maxHealth - if (maxHP == null || maxHP == 0) { - maxHP = 50 - } - - val hp = stats.hp?.let { HealthFormatter.format(it) } ?: 0.0 - valueBar.set(hp, maxHP.toDouble()) - } - private fun setUserLevel(context: Context, textView: TextView, level: Int?) { textView.text = context.getString(R.string.user_level, level) textView.contentDescription = context.getString(R.string.level_unabbreviated, level) @@ -155,8 +138,5 @@ class AvatarWithBarsViewModel(private val context: Context, private val binding: drawable?.setBounds(0, 0, drawable.minimumWidth, drawable.minimumHeight) textView.setCompoundDrawables(drawable, null, null, null) } - - private fun capitalize(s: String) = - s.substring(0, 1).toUpperCase(Locale.getDefault()) + s.substring(1) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/GemPurchaseOptionsView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/GemPurchaseOptionsView.kt index 58396d5c0..c891c23dd 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/GemPurchaseOptionsView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/GemPurchaseOptionsView.kt @@ -10,11 +10,10 @@ import com.habitrpg.android.habitica.extensions.layoutInflater class GemPurchaseOptionsView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) { - private var binding: PurchaseGemViewBinding = PurchaseGemViewBinding.inflate(context.layoutInflater, this, true) + var binding: PurchaseGemViewBinding = PurchaseGemViewBinding.inflate(context.layoutInflater, this, true) var sku: String? = null init { - val a = context.theme.obtainStyledAttributes( attrs, R.styleable.GemPurchaseOptionsView, diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/SpeechBubbleView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/SpeechBubbleView.kt index 65653a816..438bef36b 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/SpeechBubbleView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/SpeechBubbleView.kt @@ -4,59 +4,48 @@ package com.habitrpg.android.habitica.ui import android.content.Context import android.util.AttributeSet import android.view.View -import android.view.ViewGroup import android.widget.FrameLayout -import android.widget.ImageView -import android.widget.TextView import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.inflate -import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.views.Typewriter +import com.habitrpg.android.habitica.databinding.SpeechbubbleBinding +import com.habitrpg.android.habitica.extensions.layoutInflater class SpeechBubbleView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), View.OnClickListener { - - private val namePlate: TextView by bindView(R.id.name_plate) - private val textView: Typewriter by bindView(R.id.textView) - private val npcImageView: ImageView by bindView(R.id.npc_image_view) - private val confirmationButtons: ViewGroup by bindView(R.id.confirmation_buttons) - private val continueIndicator: View by bindView(R.id.continue_indicator) + internal var binding = SpeechbubbleBinding.inflate(context.layoutInflater, this, true) private var showNextListener: ShowNextListener? = null init { - inflate(R.layout.speechbubble, true) - val attributes = context.theme.obtainStyledAttributes( attrs, R.styleable.SpeechBubbleView, 0, 0) - namePlate.text = attributes.getString(R.styleable.SpeechBubbleView_namePlate) - textView.text = attributes.getString(R.styleable.SpeechBubbleView_text) + binding.namePlate.text = attributes.getString(R.styleable.SpeechBubbleView_namePlate) + binding.textView.text = attributes.getString(R.styleable.SpeechBubbleView_text) val iconRes = attributes.getDrawable(R.styleable.SpeechBubbleView_npcDrawable) if (iconRes != null) { - npcImageView.setImageDrawable(iconRes) + binding.npcImageView.setImageDrawable(iconRes) } - confirmationButtons.visibility = View.GONE + binding.confirmationButtons.visibility = View.GONE this.setOnClickListener(this) } fun setConfirmationButtonVisibility(visibility: Int) { - confirmationButtons.visibility = visibility + binding.confirmationButtons.visibility = visibility } fun animateText(text: String) { - this.textView.animateText(text) + binding.textView.animateText(text) } fun setText(text: String) { - this.textView.text = text + binding.textView.text = text } fun setHasMoreContent(hasMoreContent: Boolean) { - continueIndicator.visibility = if (hasMoreContent) View.VISIBLE else View.GONE + binding.continueIndicator.visibility = if (hasMoreContent) View.VISIBLE else View.GONE } fun setShowNextListener(listener: ShowNextListener) { @@ -64,8 +53,8 @@ class SpeechBubbleView(context: Context, attrs: AttributeSet) : FrameLayout(cont } override fun onClick(v: View) { - if (textView.isAnimating) { - textView.stopTextAnimation() + if (binding.textView.isAnimating) { + binding.textView.stopTextAnimation() } else { showNextListener?.showNextStep() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/TutorialView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/TutorialView.kt index ff35de31c..91dfffe84 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/TutorialView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/TutorialView.kt @@ -3,20 +3,13 @@ package com.habitrpg.android.habitica.ui import android.content.Context import android.view.View import android.view.ViewGroup -import android.widget.Button import android.widget.FrameLayout -import android.widget.RelativeLayout -import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.extensions.inflate +import com.habitrpg.android.habitica.databinding.OverlayTutorialBinding +import com.habitrpg.android.habitica.extensions.layoutInflater import com.habitrpg.android.habitica.models.TutorialStep -import com.habitrpg.android.habitica.ui.helpers.bindView class TutorialView(context: Context, var step: TutorialStep, var onReaction: OnTutorialReaction?) : FrameLayout(context) { - private val speechBubbleView: SpeechBubbleView by bindView(R.id.speech_bubble) - private val background: RelativeLayout by bindView(R.id.background) - private val dismissButton: Button by bindView(R.id.dismissButton) - private val completeButton: Button by bindView(R.id.completeButton) - + private val binding = OverlayTutorialBinding.inflate(context.layoutInflater, this, true) private var tutorialTexts: List = emptyList() private var currentTextIndex: Int = 0 @@ -24,22 +17,21 @@ class TutorialView(context: Context, var step: TutorialStep, var onReaction: OnT get() = currentTextIndex == tutorialTexts.size - 1 init { - inflate(R.layout.overlay_tutorial, true) - speechBubbleView.setConfirmationButtonVisibility(View.GONE) - speechBubbleView.setShowNextListener(object : SpeechBubbleView.ShowNextListener { + binding.speechBubbleView.setConfirmationButtonVisibility(View.GONE) + binding.speechBubbleView.setShowNextListener(object : SpeechBubbleView.ShowNextListener { override fun showNextStep() { displayNextTutorialText() } }) - completeButton.setOnClickListener { completeButtonClicked() } - dismissButton.setOnClickListener { dismissButtonClicked() } - background.setOnClickListener { backgroundClicked() } + binding.speechBubbleView.binding.completeButton.setOnClickListener { completeButtonClicked() } + binding.speechBubbleView.binding.dismissButton.setOnClickListener { dismissButtonClicked() } + binding.background.setOnClickListener { backgroundClicked() } } fun setTutorialText(text: String) { - this.speechBubbleView.animateText(text) - speechBubbleView.setConfirmationButtonVisibility(View.VISIBLE) + binding.speechBubbleView.animateText(text) + binding.speechBubbleView.setConfirmationButtonVisibility(View.VISIBLE) } fun setTutorialTexts(texts: List ) { @@ -49,18 +41,18 @@ class TutorialView(context: Context, var step: TutorialStep, var onReaction: OnT } fun setCanBeDeferred(canBeDeferred: Boolean) { - dismissButton.visibility = if (canBeDeferred) View.VISIBLE else View.GONE + binding.speechBubbleView.binding.dismissButton.visibility = if (canBeDeferred) View.VISIBLE else View.GONE } private fun displayNextTutorialText() { currentTextIndex++ if (currentTextIndex < tutorialTexts.size) { - speechBubbleView.animateText(tutorialTexts[currentTextIndex]) + binding.speechBubbleView.animateText(tutorialTexts[currentTextIndex]) if (isDisplayingLastStep) { - speechBubbleView.setConfirmationButtonVisibility(View.VISIBLE) - speechBubbleView.setHasMoreContent(false) + binding.speechBubbleView.setConfirmationButtonVisibility(View.VISIBLE) + binding.speechBubbleView.setHasMoreContent(false) } else { - speechBubbleView.setHasMoreContent(true) + binding.speechBubbleView.setHasMoreContent(true) } } else { this.onReaction?.onTutorialCompleted(this.step) @@ -78,7 +70,7 @@ class TutorialView(context: Context, var step: TutorialStep, var onReaction: OnT } private fun backgroundClicked() { - speechBubbleView.onClick(speechBubbleView) + binding.speechBubbleView.onClick(binding.speechBubbleView) } interface OnTutorialReaction { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AboutActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AboutActivity.kt deleted file mode 100644 index 6db1df3c6..000000000 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AboutActivity.kt +++ /dev/null @@ -1,111 +0,0 @@ -package com.habitrpg.android.habitica.ui.activities - -import android.os.Bundle -import android.view.MenuItem -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentStatePagerAdapter -import androidx.viewpager.widget.ViewPager -import com.google.android.material.tabs.TabLayout -import com.habitrpg.android.habitica.R -import com.habitrpg.android.habitica.components.UserComponent -import com.habitrpg.android.habitica.ui.fragments.AboutFragment -import com.habitrpg.android.habitica.ui.helpers.bindView -import com.mikepenz.aboutlibraries.Libs -import com.mikepenz.aboutlibraries.LibsBuilder - -class AboutActivity : BaseActivity() { - - private val pager: ViewPager by bindView(R.id.pager) - private val tabLayout: TabLayout by bindView(R.id.tab_layout) - - override fun getLayoutResId(): Int { - return R.layout.activity_about - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - val actionBar = supportActionBar - if (actionBar != null) { - actionBar.setTitle(R.string.about_title) - actionBar.setDisplayHomeAsUpEnabled(true) - actionBar.setDisplayShowHomeEnabled(false) - actionBar.setDisplayShowTitleEnabled(true) - actionBar.setDisplayUseLogoEnabled(false) - actionBar.setHomeButtonEnabled(false) - actionBar.elevation = 0f - } - - tabLayout.tabGravity = TabLayout.GRAVITY_FILL - - val adapter = PagerAdapter(supportFragmentManager, 2) - pager.adapter = adapter - pager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabLayout)) - pager.offscreenPageLimit = 1 - - tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { - override fun onTabSelected(tab: TabLayout.Tab) { - pager.currentItem = tab.position - } - - override fun onTabUnselected(tab: TabLayout.Tab) { /* no-on */ } - - override fun onTabReselected(tab: TabLayout.Tab) { /* no-on */ } - }) - - tabLayout.setupWithViewPager(pager) - } - - override fun injectActivity(component: UserComponent?) { - component?.inject(this) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - val id = item.itemId - - - if (id == android.R.id.home) { - finish() - return true - } - - return super.onOptionsItemSelected(item) - } - - private inner class PagerAdapter(fm: FragmentManager, internal var mNumOfTabs: Int) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - - override fun getItem(position: Int): Fragment { - return when (position) { - 0 -> AboutFragment() - 1 -> LibsBuilder() - //Pass the fields of your application to the lib so it can find all external lib information - .withFields(R.string::class.java.fields) - .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) - .withAboutAppName(getString(R.string.app_name)) - .withAboutDescription(" Used Libraries
") - .withAboutIconShown(true) - .withAboutVersionShown(true) - .withAboutVersionShownCode(true) - .withAboutVersionShownName(true) - .supportFragment() - else -> Fragment() - } - } - - override fun getPageTitle(position: Int): CharSequence? { - return when (position) { - 0 -> getString(R.string.about_title) - 1 -> getString(R.string.about_libraries) - else -> "" - } - } - - override fun getCount(): Int { - return mNumOfTabs - } - } -} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AddTaskWidgetActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AddTaskWidgetActivity.kt index 93819e3e5..a6fcdd5d1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AddTaskWidgetActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AddTaskWidgetActivity.kt @@ -5,27 +5,23 @@ import android.appwidget.AppWidgetManager import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import androidx.preference.PreferenceManager -import android.widget.Button import androidx.core.content.edit -import com.habitrpg.android.habitica.R +import androidx.preference.PreferenceManager +import com.habitrpg.android.habitica.databinding.WidgetConfigureAddTaskBinding import com.habitrpg.android.habitica.models.tasks.Task -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.widget.AddTaskWidgetProvider class AddTaskWidgetActivity : AppCompatActivity() { private var widgetId: Int = 0 - private val addHabitButton: Button by bindView(R.id.add_habit_button) - private val addDailyButton: Button by bindView(R.id.add_daily_button) - private val addToDoButton: Button by bindView(R.id.add_todo_button) - private val addRewardButton: Button by bindView(R.id.add_reward_button) + private lateinit var binding: WidgetConfigureAddTaskBinding public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setResult(Activity.RESULT_CANCELED) - setContentView(R.layout.widget_configure_add_task) + binding = WidgetConfigureAddTaskBinding.inflate(layoutInflater) + setContentView(binding.root) val intent = intent val extras = intent.extras @@ -39,10 +35,10 @@ class AddTaskWidgetActivity : AppCompatActivity() { finish() } - addHabitButton.setOnClickListener { addHabitSelected() } - addDailyButton.setOnClickListener { addDailySelected() } - addToDoButton.setOnClickListener { addToDoSelected() } - addRewardButton.setOnClickListener { addRewardSelected() } + binding.addHabitButton.setOnClickListener { addHabitSelected() } + binding.addDailyButton.setOnClickListener { addDailySelected() } + binding.addTodoButton.setOnClickListener { addToDoSelected() } + binding.addRewardButton.setOnClickListener { addRewardSelected() } } private fun addHabitSelected() { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AdventureGuideActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AdventureGuideActivity.kt index 7553900bc..bc2e1f736 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AdventureGuideActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/AdventureGuideActivity.kt @@ -18,7 +18,6 @@ import com.habitrpg.android.habitica.databinding.AdventureGuideItemBinding import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils -import io.reactivex.functions.Consumer import javax.inject.Inject @@ -85,7 +84,7 @@ class AdventureGuideActivity : BaseActivity() { override fun onStart() { super.onStart() - compositeSubscription.add(userRepository.getUser().subscribe(Consumer { + compositeSubscription.add(userRepository.getUser().subscribe({ updateUser(it) }, RxErrorHandler.handleEmptyError())) } @@ -118,11 +117,11 @@ class AdventureGuideActivity : BaseActivity() { DataBindingUtils.loadImage(itemBinding.iconView, iconName) if (achievement.earned) { itemBinding.titleView.paintFlags = itemBinding.titleView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG - itemBinding.titleView.setTextColor(ContextCompat.getColor(this, R.color.gray_200)) - itemBinding.descriptionView.setTextColor(ContextCompat.getColor(this, R.color.gray_200)) + itemBinding.titleView.setTextColor(ContextCompat.getColor(this, R.color.text_ternary)) + itemBinding.descriptionView.setTextColor(ContextCompat.getColor(this, R.color.text_ternary)) } else { - itemBinding.titleView.setTextColor(ContextCompat.getColor(this, R.color.gray_50)) - itemBinding.descriptionView.setTextColor(ContextCompat.getColor(this, R.color.gray_50)) + itemBinding.titleView.setTextColor(ContextCompat.getColor(this, R.color.text_primary)) + itemBinding.descriptionView.setTextColor(ContextCompat.getColor(this, R.color.text_primary)) itemBinding.iconView.alpha = 0.5f } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt index b6e09c928..7ef143ced 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/BaseActivity.kt @@ -3,12 +3,14 @@ package com.habitrpg.android.habitica.ui.activities import android.content.Context import android.content.SharedPreferences import android.content.res.Configuration +import android.content.res.Resources import android.os.Bundle import android.view.LayoutInflater import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.widget.Toolbar +import androidx.core.content.ContextCompat import androidx.preference.PreferenceManager import com.habitrpg.android.habitica.HabiticaApplication import com.habitrpg.android.habitica.HabiticaBaseApplication @@ -16,7 +18,10 @@ import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.events.ShowConnectionProblemEvent import com.habitrpg.android.habitica.extensions.getThemeColor +import com.habitrpg.android.habitica.extensions.isUsingNightModeResources +import com.habitrpg.android.habitica.extensions.updateStatusBarColor import com.habitrpg.android.habitica.helpers.LanguageHelper +import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.disposables.CompositeDisposable import org.greenrobot.eventbus.EventBus @@ -27,9 +32,12 @@ import java.util.* abstract class BaseActivity : AppCompatActivity() { private var currentTheme: String? = null + private var isNightMode: Boolean = false internal var forcedTheme: String? = null private var destroyed: Boolean = false + open var overrideModernHeader: Boolean? = null + protected abstract fun getLayoutResId(): Int open fun getContentView(): View { @@ -50,13 +58,15 @@ abstract class BaseActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) val languageHelper = LanguageHelper(sharedPreferences.getString("language", "en")) - Locale.setDefault(languageHelper.locale) - val configuration = Configuration() - configuration.setLocale(languageHelper.locale) - resources.updateConfiguration(configuration, resources.displayMetrics) + resources.forceLocale(languageHelper.locale) + delegate.localNightMode = when (sharedPreferences.getString("theme_mode", "system")) { + "light" -> AppCompatDelegate.MODE_NIGHT_NO + "dark" -> AppCompatDelegate.MODE_NIGHT_YES + else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM + } + isNightMode = isUsingNightModeResources() loadTheme(sharedPreferences) - delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_NO super.onCreate(savedInstanceState) habiticaApplication injectActivity(HabiticaBaseApplication.userComponent) @@ -75,6 +85,7 @@ abstract class BaseActivity : AppCompatActivity() { loadTheme(PreferenceManager.getDefaultSharedPreferences(this)) } + override fun onPause() { isActivityVisible = false super.onPause() @@ -87,27 +98,47 @@ abstract class BaseActivity : AppCompatActivity() { super.onStop() } - private fun loadTheme(sharedPreferences: SharedPreferences) { - val theme = if (forcedTheme != null) { - forcedTheme - } else { - sharedPreferences.getString("theme_name", "purple") + internal open fun loadTheme(sharedPreferences: SharedPreferences, forced: Boolean = false) { + val theme = forcedTheme ?: sharedPreferences.getString("theme_name", "purple") + val modernHeaderStyle = overrideModernHeader ?: sharedPreferences.getBoolean("modern_header_style", true) + if (theme != currentTheme || forced) { + if (isNightMode) { + setTheme(when (theme) { + "maroon" -> R.style.MainAppTheme_Maroon_Dark + "red" -> R.style.MainAppTheme_Red_Dark + "orange" -> R.style.MainAppTheme_Orange_Dark + "yellow" -> R.style.MainAppTheme_Yellow_Dark + "green" -> R.style.MainAppTheme_Green_Dark + "teal" -> R.style.MainAppTheme_Teal_Dark + "blue" -> R.style.MainAppTheme_Blue_Dark + else -> R.style.MainAppTheme_Dark + }) + } else { + setTheme(when (theme) { + "maroon" -> R.style.MainAppTheme_Maroon + "red" -> R.style.MainAppTheme_Red + "orange" -> R.style.MainAppTheme_Orange + "yellow" -> R.style.MainAppTheme_Yellow + "green" -> R.style.MainAppTheme_Green + "teal" -> R.style.MainAppTheme_Teal + "blue" -> R.style.MainAppTheme_Blue + else -> R.style.MainAppTheme + }) + } } - if (theme == currentTheme) return - setTheme(when (theme) { - "maroon" -> R.style.MainAppTheme_Maroon - "red" -> R.style.MainAppTheme_Red - "orange" -> R.style.MainAppTheme_Orange - "yellow" -> R.style.MainAppTheme_Yellow - "green" -> R.style.MainAppTheme_Green - "teal" -> R.style.MainAppTheme_Teal - "blue" -> R.style.MainAppTheme_Blue - else -> R.style.MainAppTheme - }) - window.navigationBarColor = getThemeColor(R.attr.colorPrimaryDark) - window.statusBarColor = getThemeColor(R.attr.colorPrimaryDark) - if (currentTheme != null) { + if (isNightMode) { + window.navigationBarColor = ContextCompat.getColor(this, R.color.system_bars) + } else { + window.navigationBarColor = getThemeColor(R.attr.colorPrimaryDark) + } + if (!isNightMode && modernHeaderStyle) { + window.updateStatusBarColor(getThemeColor(R.attr.headerBackgroundColor), true) + } else { + window.updateStatusBarColor(getThemeColor(R.attr.statusBarBackground), false) + } + + if (currentTheme != null && theme != currentTheme) { reload() } else { currentTheme = theme @@ -129,6 +160,7 @@ abstract class BaseActivity : AppCompatActivity() { actionBar.setHomeButtonEnabled(true) } } + toolbar?.let { ToolbarColorHelper.colorizeToolbar(it, this, overrideModernHeader) } } override fun onDestroy() { @@ -140,6 +172,16 @@ abstract class BaseActivity : AppCompatActivity() { super.onDestroy() } + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + val newNightMode = isUsingNightModeResources() + if (newNightMode != isNightMode) { + isNightMode = newNightMode + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) + loadTheme(sharedPreferences, true) + } + } + @Subscribe open fun onEvent(event: ShowConnectionProblemEvent) { val alert = HabiticaAlertDialog(this) @@ -155,3 +197,10 @@ abstract class BaseActivity : AppCompatActivity() { startActivity(intent) } } + +private fun Resources.forceLocale(locale: Locale) { + Locale.setDefault(locale) + val configuration = Configuration() + configuration.setLocale(locale) + updateConfiguration(configuration, displayMetrics) +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeFormActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeFormActivity.kt index a3a82706e..80747891f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeFormActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ChallengeFormActivity.kt @@ -7,16 +7,18 @@ import android.content.Intent import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.* -import android.widget.* +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.EditText import androidx.appcompat.widget.AppCompatCheckedTextView import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.Toolbar -import com.google.android.material.textfield.TextInputLayout import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.ChallengeRepository import com.habitrpg.android.habitica.data.SocialRepository import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.databinding.ActivityCreateChallengeBinding import com.habitrpg.android.habitica.extensions.getThemeColor import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.social.Challenge @@ -25,31 +27,19 @@ import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.adapter.social.challenges.ChallengeTasksRecyclerViewAdapter -import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.Flowable -import io.reactivex.functions.Consumer +import io.reactivex.rxkotlin.zipWith import java.util.* import javax.inject.Inject import javax.inject.Named class ChallengeFormActivity : BaseActivity() { - private val createChallengeTitleInputLayout: TextInputLayout by bindView(R.id.create_challenge_title_input_layout) - private val createChallengeTitle: EditText by bindView(R.id.create_challenge_title) - private val createChallengeDescription: EditText by bindView(R.id.create_challenge_description) - private val createChallengePrize: EditText by bindView(R.id.create_challenge_prize) - private val createChallengeTagInputLayout: TextInputLayout by bindView(R.id.create_challenge_tag_input_layout) - private val createChallengeTag: EditText by bindView(R.id.create_challenge_tag) - private val createChallengeGemError: TextView by bindView(R.id.create_challenge_gem_error) - private val createChallengeTaskError: TextView by bindView(R.id.create_challenge_task_error) - private val challengeLocationSpinner: Spinner by bindView(R.id.challenge_location_spinner) - private val challengeAddGemBtn: Button by bindView(R.id.challenge_add_gem_btn) - private val challengeRemoveGemBtn: Button by bindView(R.id.challenge_remove_gem_btn) - private val createChallengeTaskList: androidx.recyclerview.widget.RecyclerView by bindView(R.id.create_challenge_task_list) - private val gemIconView: ImageView by bindView(R.id.gem_icon) - private val challengeCreationViews: ViewGroup by bindView(R.id.challenge_creation_views) + + private lateinit var binding: ActivityCreateChallengeBinding @Inject internal lateinit var challengeRepository: ChallengeRepository @@ -71,6 +61,7 @@ class ChallengeFormActivity : BaseActivity() { private val updatedTasks = HashMap() private val removedTasks = HashMap () + override var overrideModernHeader: Boolean? = true // Add {*} Items private var addHabit: Task? = null private var addDaily: Task? = null @@ -80,11 +71,16 @@ class ChallengeFormActivity : BaseActivity() { private var savingInProgress = false + override fun getContentView(): View { + binding = ActivityCreateChallengeBinding.inflate(layoutInflater) + return binding.root + } + private val challengeData: Challenge get() { val c = Challenge() - val locationPos = challengeLocationSpinner.selectedItemPosition + val locationPos = binding.challengeLocationSpinner.selectedItemPosition if (challengeId != null) { c.id = challengeId @@ -98,10 +94,10 @@ class ChallengeFormActivity : BaseActivity() { c.groupId = locationGroup.id } } - c.name = createChallengeTitle.text.toString() - c.description = createChallengeDescription.text.toString() - c.shortName = createChallengeTag.text.toString() - c.prize = Integer.parseInt(createChallengePrize.text.toString()) + c.name = binding.createChallengeTitle.text.toString() + c.description = binding.createChallengeDescription.text.toString() + c.shortName = binding.createChallengeTag.text.toString() + c.prize = Integer.parseInt(binding.createChallengePrize.text.toString()) return c } @@ -117,6 +113,7 @@ class ChallengeFormActivity : BaseActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater = menuInflater inflater.inflate(R.menu.menu_create_challenge, menu) + findViewById (R.id.toolbar).let { ToolbarColorHelper.colorizeToolbar(it, this, overrideModernHeader) } return true } @@ -165,21 +162,21 @@ class ChallengeFormActivity : BaseActivity() { private fun validateAllFields(): Boolean { val errorMessages = ArrayList () - if (getEditTextString(createChallengeTitle).isEmpty()) { + if (getEditTextString(binding.createChallengeTitle).isEmpty()) { val titleEmptyError = getString(R.string.challenge_create_error_title) - createChallengeTitleInputLayout.error = titleEmptyError + binding.createChallengeTitleInputLayout.error = titleEmptyError errorMessages.add(titleEmptyError) } else { - createChallengeTitleInputLayout.isErrorEnabled = false + binding.createChallengeTitleInputLayout.isErrorEnabled = false } - if (getEditTextString(createChallengeTag).isEmpty()) { + if (getEditTextString(binding.createChallengeTag).isEmpty()) { val tagEmptyError = getString(R.string.challenge_create_error_tag) - createChallengeTagInputLayout.error = tagEmptyError + binding.createChallengeTagInputLayout.error = tagEmptyError errorMessages.add(tagEmptyError) } else { - createChallengeTagInputLayout.isErrorEnabled = false + binding.createChallengeTagInputLayout.isErrorEnabled = false } val prizeError = checkPrizeAndMinimumForTavern() @@ -190,10 +187,10 @@ class ChallengeFormActivity : BaseActivity() { // all "Add {*}"-Buttons are one task itself, so we need atleast more than 4 if (challengeTasks.taskList.size <= 4) { - createChallengeTaskError.visibility = View.VISIBLE + binding.createChallengeTaskError.visibility = View.VISIBLE errorMessages.add(getString(R.string.challenge_create_error_no_tasks)) } else { - createChallengeTaskError.visibility = View.GONE + binding.createChallengeTaskError.visibility = View.GONE } if (errorMessages.count() > 0) { val alert = HabiticaAlertDialog(this) @@ -212,7 +209,7 @@ class ChallengeFormActivity : BaseActivity() { val intent = intent val bundle = intent.extras - challengeTasks = ChallengeTasksRecyclerViewAdapter(null, 0, this, "", null, false, true) + challengeTasks = ChallengeTasksRecyclerViewAdapter(null, 0, this, "", false, true) compositeSubscription.add(challengeTasks.taskOpenEvents.subscribe { if (it.isValid) { openNewTaskActivity(it.type, it) @@ -230,11 +227,11 @@ class ChallengeFormActivity : BaseActivity() { fillControlsByChallenge() } - compositeSubscription.add(userRepository.getUser(userId).subscribe(Consumer { this.user = it }, RxErrorHandler.handleEmptyError())) - gemIconView.setImageBitmap(HabiticaIconsHelper.imageOfGem()) + compositeSubscription.add(userRepository.getUser(userId).subscribe({ this.user = it }, RxErrorHandler.handleEmptyError())) + binding.gemIconView.setImageBitmap(HabiticaIconsHelper.imageOfGem()) - challengeAddGemBtn.setOnClickListener { onAddGem() } - challengeRemoveGemBtn.setOnClickListener { onRemoveGem() } + binding.challengeAddGemBtn.setOnClickListener { onAddGem() } + binding.challengeRemoveGemBtn.setOnClickListener { onRemoveGem() } } @@ -245,27 +242,27 @@ class ChallengeFormActivity : BaseActivity() { } private fun onAddGem() { - var stringValue = createChallengePrize.text.toString() + var stringValue = binding.createChallengePrize.text.toString() if (stringValue.isEmpty()) { stringValue = "0" } var currentVal = Integer.parseInt(stringValue) currentVal++ - createChallengePrize.setText(currentVal.toString()) + binding.createChallengePrize.setText(currentVal.toString()) checkPrizeAndMinimumForTavern() } private fun onRemoveGem() { - var stringValue = createChallengePrize.text.toString() + var stringValue = binding.createChallengePrize.text.toString() if (stringValue.isEmpty()) { stringValue = "0" } var currentVal = Integer.parseInt(stringValue) currentVal-- - createChallengePrize.setText(currentVal.toString()) + binding.createChallengePrize.setText(currentVal.toString()) checkPrizeAndMinimumForTavern() } @@ -273,7 +270,7 @@ class ChallengeFormActivity : BaseActivity() { private fun checkPrizeAndMinimumForTavern(): String { var errorResult = "" - var inputValue = createChallengePrize.text.toString() + var inputValue = binding.createChallengePrize.text.toString() if (inputValue.isEmpty()) { inputValue = "0" @@ -282,25 +279,25 @@ class ChallengeFormActivity : BaseActivity() { val currentVal = Integer.parseInt(inputValue) // 0 is Tavern - val selectedLocation = challengeLocationSpinner.selectedItemPosition + val selectedLocation = binding.challengeLocationSpinner.selectedItemPosition val gemCount = user?.gemCount?.toDouble() ?: 0.toDouble() if (selectedLocation == 0 && currentVal == 0) { - createChallengeGemError.visibility = View.VISIBLE + binding.createChallengeGemError.visibility = View.VISIBLE val error = getString(R.string.challenge_create_error_tavern_one_gem) - createChallengeGemError.text = error + binding.createChallengeGemError.text = error errorResult = error } else if (currentVal > gemCount) { - createChallengeGemError.visibility = View.VISIBLE + binding.createChallengeGemError.visibility = View.VISIBLE val error = getString(R.string.challenge_create_error_enough_gems) - createChallengeGemError.text = error + binding.createChallengeGemError.text = error errorResult = error } else { - createChallengeGemError.visibility = View.GONE + binding.createChallengeGemError.visibility = View.GONE } - challengeRemoveGemBtn.isEnabled = currentVal != 0 + binding.challengeRemoveGemBtn.isEnabled = currentVal != 0 return errorResult } @@ -319,28 +316,39 @@ class ChallengeFormActivity : BaseActivity() { } locationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - compositeSubscription.add(socialRepository.getGroups("guild").subscribe(Consumer { groups -> - val mutableGroups = groups.toMutableList() - if (groups.firstOrNull { it.id == "00000000-0000-4000-A000-000000000000" } == null) { + compositeSubscription.add(socialRepository.getUserGroups("guild").zipWith(userRepository.getUser() + .map { "" } + .distinctUntilChanged() + .flatMap { + if (it.isBlank()) { + return@flatMap Flowable.empty () + } + socialRepository.retrieveGroup(it) + }) + .subscribe({ groups -> + val mutableGroups = groups.first.toMutableList() + if (groups.first.firstOrNull { it.id == "00000000-0000-4000-A000-000000000000" } == null) { val tavern = Group() tavern.id = "00000000-0000-4000-A000-000000000000" tavern.name = getString(R.string.public_challenge) mutableGroups.add(0, tavern) } - + if (groups.second != null) { + mutableGroups.add(groups.second) + } locationAdapter.clear() locationAdapter.addAll(mutableGroups) }, RxErrorHandler.handleEmptyError())) - challengeLocationSpinner.adapter = locationAdapter - challengeLocationSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + binding.challengeLocationSpinner.adapter = locationAdapter + binding.challengeLocationSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(adapterView: AdapterView<*>, view: View?, i: Int, l: Long) { checkPrizeAndMinimumForTavern() } override fun onNothingSelected(adapterView: AdapterView<*>) { /* no-on */ } } - createChallengePrize.setOnKeyListener { _, _, _ -> + binding.createChallengePrize.setOnKeyListener { _, _, _ -> checkPrizeAndMinimumForTavern() false @@ -359,7 +367,7 @@ class ChallengeFormActivity : BaseActivity() { addReward?.let { taskList.add(it) } challengeTasks.setTasks(taskList) - compositeSubscription.add(challengeTasks.addItemObservable().subscribe(Consumer { t -> + compositeSubscription.add(challengeTasks.addItemObservable().subscribe({ t -> when (t) { addHabit -> openNewTaskActivity(Task.TYPE_HABIT, null) addDaily -> openNewTaskActivity(Task.TYPE_DAILY, null) @@ -368,38 +376,38 @@ class ChallengeFormActivity : BaseActivity() { } }, RxErrorHandler.handleEmptyError())) - createChallengeTaskList.addOnItemTouchListener(object : androidx.recyclerview.widget.RecyclerView.SimpleOnItemTouchListener() { + binding.createChallengeTaskList.addOnItemTouchListener(object : androidx.recyclerview.widget.RecyclerView.SimpleOnItemTouchListener() { override fun onInterceptTouchEvent(rv: androidx.recyclerview.widget.RecyclerView, e: MotionEvent): Boolean { // Stop only scrolling. return rv.scrollState == androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING } }) - createChallengeTaskList.adapter = challengeTasks - createChallengeTaskList.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this) + binding.createChallengeTaskList.adapter = challengeTasks + binding.createChallengeTaskList.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this) } private fun fillControlsByChallenge() { challengeId?.let { - challengeRepository.getChallenge(it).subscribe(Consumer { challenge -> + challengeRepository.getChallenge(it).subscribe({ challenge -> groupID = challenge.groupId editMode = true - createChallengeTitle.setText(challenge.name) - createChallengeDescription.setText(challenge.description) - createChallengeTag.setText(challenge.shortName) - createChallengePrize.setText(challenge.prize.toString()) - challengeCreationViews.visibility = View.GONE + binding.createChallengeTitle.setText(challenge.name) + binding.createChallengeDescription.setText(challenge.description) + binding.createChallengeTag.setText(challenge.shortName) + binding.createChallengePrize.setText(challenge.prize.toString()) + binding.challengeCreationViews.visibility = View.GONE for (i in 0 until locationAdapter.count) { val group = locationAdapter.getItem(i) if (group != null && challenge.groupId == group.id) { - challengeLocationSpinner.setSelection(i) + binding.challengeLocationSpinner.setSelection(i) break } } checkPrizeAndMinimumForTavern() }, RxErrorHandler.handleEmptyError()) - challengeRepository.getChallengeTasks(it).subscribe(Consumer { tasks -> + challengeRepository.getChallengeTasks(it).subscribe({ tasks -> tasks.forEach { task -> addOrUpdateTaskInList(task, true) } @@ -483,7 +491,7 @@ class ChallengeFormActivity : BaseActivity() { return editText.text.toString() } - private inner class GroupArrayAdapter internal constructor(context: Context) : ArrayAdapter (context, android.R.layout.simple_spinner_item) { + private class GroupArrayAdapter(context: Context) : ArrayAdapter (context, android.R.layout.simple_spinner_item) { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val checkedTextView = super.getView(position, convertView, parent) as? AppCompatTextView diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ClassSelectionActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ClassSelectionActivity.kt index 1ea1ea435..523a18268 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ClassSelectionActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ClassSelectionActivity.kt @@ -7,19 +7,15 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View -import android.view.ViewGroup -import android.widget.Button import android.widget.TextView -import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.navigation.navArgs import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.databinding.ActivityClassSelectionBinding import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.user.* -import com.habitrpg.android.habitica.ui.AvatarView -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.functions.Consumer @@ -27,6 +23,7 @@ import javax.inject.Inject class ClassSelectionActivity : BaseActivity(), Consumer { + private lateinit var binding: ActivityClassSelectionBinding private var currentClass: String? = null private var newClass: String = "healer" set(value) { @@ -42,32 +39,13 @@ class ClassSelectionActivity : BaseActivity(), Consumer { private var className: String? = null set(value) { field = value - selectedTitleTextView.text = getString(R.string.x_class, className) - selectedButton.text = getString(R.string.become_x, className) + binding.selectedTitleTextView.text = getString(R.string.x_class, className) + binding.selectedButton.text = getString(R.string.become_x, className) } private var isInitialSelection: Boolean = false private var classWasUnset: Boolean? = false private var shouldFinish: Boolean? = false - private val toolbar: Toolbar by bindView(R.id.toolbar) - private val healerAvatarView: AvatarView by bindView(R.id.healerAvatarView) - private val healerWrapper: View by bindView(R.id.healerWrapper) - private val healerButton: TextView by bindView(R.id.healerButton) - private val mageAvatarView: AvatarView by bindView(R.id.mageAvatarView) - private val mageWrapper: View by bindView(R.id.mageWrapper) - private val mageButton: TextView by bindView(R.id.mageButton) - private val rogueAvatarView: AvatarView by bindView(R.id.rogueAvatarView) - private val rogueWrapper: View by bindView(R.id.rogueWrapper) - private val rogueButton: TextView by bindView(R.id.rogueButton) - private val warriorAvatarView: AvatarView by bindView(R.id.warriorAvatarView) - private val warriorWrapper: View by bindView(R.id.warriorWrapper) - private val warriorButton: TextView by bindView(R.id.warriorButton) - - private val selectedWrapperView: ViewGroup by bindView(R.id.selected_wrapper) - private val selectedTitleTextView: TextView by bindView(R.id.selected_title_textview) - private val selectedDescriptionTextView: TextView by bindView(R.id.selected_description_textview) - private val selectedButton: Button by bindView(R.id.selected_button) - @Inject lateinit var userRepository: UserRepository @@ -78,9 +56,14 @@ class ClassSelectionActivity : BaseActivity(), Consumer { return R.layout.activity_class_selection } + override fun getContentView(): View { + binding = ActivityClassSelectionBinding.inflate(layoutInflater) + return binding.root + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true) @@ -88,7 +71,7 @@ class ClassSelectionActivity : BaseActivity(), Consumer { isInitialSelection = args.isInitialSelection currentClass = args.className - compositeSubscription.add(userRepository.getUser().firstElement().subscribe(Consumer { + compositeSubscription.add(userRepository.getUser().firstElement().subscribe({ it.preferences?.let {preferences -> val unmanagedPrefs = userRepository.getUnmanagedCopy(preferences) unmanagedPrefs.costume = false @@ -98,14 +81,14 @@ class ClassSelectionActivity : BaseActivity(), Consumer { if (!isInitialSelection) { compositeSubscription.add(userRepository.changeClass() - .subscribe(Consumer { classWasUnset = true }, RxErrorHandler.handleEmptyError())) + .subscribe({ classWasUnset = true }, RxErrorHandler.handleEmptyError())) } - healerWrapper.setOnClickListener { newClass = "healer" } - mageWrapper.setOnClickListener { newClass = "wizard" } - rogueWrapper.setOnClickListener { newClass = "rogue" } - warriorWrapper.setOnClickListener { newClass = "warrior" } - selectedButton.setOnClickListener { displayConfirmationDialogForClass() } + binding.healerWrapper.setOnClickListener { newClass = "healer" } + binding.mageWrapper.setOnClickListener { newClass = "wizard" } + binding.rogueWrapper.setOnClickListener { newClass = "rogue" } + binding.warriorWrapper.setOnClickListener { newClass = "warrior" } + binding.selectedButton.setOnClickListener { displayConfirmationDialogForClass() } } override fun onStart() { @@ -120,7 +103,7 @@ class ClassSelectionActivity : BaseActivity(), Consumer { } override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item?.itemId) { + when (item.itemId) { R.id.opt_out -> optOutSelected() } return super.onOptionsItemSelected(item) @@ -133,18 +116,18 @@ class ClassSelectionActivity : BaseActivity(), Consumer { healerOutfit.shield = "shield_healer_5" healerOutfit.weapon = "weapon_healer_6" val healer = this.makeUser(preferences, healerOutfit) - healerAvatarView.setAvatar(healer) + binding.healerAvatarView.setAvatar(healer) val healerIcon = BitmapDrawable(resources, HabiticaIconsHelper.imageOfHealerLightBg()) - healerButton.setCompoundDrawablesWithIntrinsicBounds(healerIcon, null, null, null) + binding.healerButton.setCompoundDrawablesWithIntrinsicBounds(healerIcon, null, null, null) val mageOutfit = Outfit() mageOutfit.armor = "armor_wizard_5" mageOutfit.head = "head_wizard_5" mageOutfit.weapon = "weapon_wizard_6" val mage = this.makeUser(preferences, mageOutfit) - mageAvatarView.setAvatar(mage) + binding.mageAvatarView.setAvatar(mage) val mageIcon = BitmapDrawable(resources, HabiticaIconsHelper.imageOfMageLightBg()) - mageButton.setCompoundDrawablesWithIntrinsicBounds(mageIcon, null, null, null) + binding.mageButton.setCompoundDrawablesWithIntrinsicBounds(mageIcon, null, null, null) val rogueOutfit = Outfit() rogueOutfit.armor = "armor_rogue_5" @@ -152,9 +135,9 @@ class ClassSelectionActivity : BaseActivity(), Consumer { rogueOutfit.shield = "shield_rogue_6" rogueOutfit.weapon = "weapon_rogue_6" val rogue = this.makeUser(preferences, rogueOutfit) - rogueAvatarView.setAvatar(rogue) + binding.rogueAvatarView.setAvatar(rogue) val rogueIcon = BitmapDrawable(resources, HabiticaIconsHelper.imageOfRogueLightBg()) - rogueButton.setCompoundDrawablesWithIntrinsicBounds(rogueIcon, null, null, null) + binding.rogueButton.setCompoundDrawablesWithIntrinsicBounds(rogueIcon, null, null, null) val warriorOutfit = Outfit() warriorOutfit.armor = "armor_warrior_5" @@ -162,9 +145,9 @@ class ClassSelectionActivity : BaseActivity(), Consumer { warriorOutfit.shield = "shield_warrior_5" warriorOutfit.weapon = "weapon_warrior_6" val warrior = this.makeUser(preferences, warriorOutfit) - warriorAvatarView.setAvatar(warrior) + binding.warriorAvatarView.setAvatar(warrior) val warriorIcon = BitmapDrawable(resources, HabiticaIconsHelper.imageOfWarriorLightBg()) - warriorButton.setCompoundDrawablesWithIntrinsicBounds(warriorIcon, null, null, null) + binding.warriorButton.setCompoundDrawablesWithIntrinsicBounds(warriorIcon, null, null, null) } override fun injectActivity(component: UserComponent?) { @@ -182,50 +165,50 @@ class ClassSelectionActivity : BaseActivity(), Consumer { private fun healerSelected() { className = getString(R.string.healer) - selectedDescriptionTextView.text = getString(R.string.healer_description) - selectedWrapperView.setBackgroundColor(ContextCompat.getColor(this, R.color.yellow_100)) - selectedTitleTextView.setTextColor(ContextCompat.getColor(this, R.color.dark_brown)) - selectedDescriptionTextView.setTextColor(ContextCompat.getColor(this, R.color.dark_brown)) - selectedButton.setBackgroundResource(R.drawable.layout_rounded_bg_yellow_10) - updateButtonBackgrounds(healerButton, getDrawable(R.drawable.layout_rounded_bg_brand_700_yellow_border)) + binding.selectedDescriptionTextView.text = getString(R.string.healer_description) + binding.selectedWrapperView.setBackgroundColor(ContextCompat.getColor(this, R.color.yellow_100)) + binding.selectedTitleTextView.setTextColor(ContextCompat.getColor(this, R.color.dark_brown)) + binding.selectedDescriptionTextView.setTextColor(ContextCompat.getColor(this, R.color.dark_brown)) + binding.selectedButton.setBackgroundResource(R.drawable.layout_rounded_bg_yellow_10) + updateButtonBackgrounds(binding.healerButton, ContextCompat.getDrawable(this,R.drawable.layout_rounded_bg_window_yellow_border)) } private fun mageSelected() { className = getString(R.string.mage) - selectedDescriptionTextView.text = getString(R.string.mage_description) - selectedWrapperView.setBackgroundColor(ContextCompat.getColor(this, R.color.blue_10)) - selectedTitleTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) - selectedDescriptionTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) - selectedButton.setBackgroundResource(R.drawable.layout_rounded_bg_gray_alpha) - updateButtonBackgrounds(mageButton, getDrawable(R.drawable.layout_rounded_bg_brand_700_blue_border)) + binding.selectedDescriptionTextView.text = getString(R.string.mage_description) + binding.selectedWrapperView.setBackgroundColor(ContextCompat.getColor(this, R.color.blue_10)) + binding.selectedTitleTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) + binding.selectedDescriptionTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) + binding.selectedButton.setBackgroundResource(R.drawable.layout_rounded_bg_gray_alpha) + updateButtonBackgrounds(binding.mageButton, ContextCompat.getDrawable(this,R.drawable.layout_rounded_bg_window_blue_border)) } private fun rogueSelected() { className = getString(R.string.rogue) - selectedDescriptionTextView.text = getString(R.string.rogue_description) - selectedWrapperView.setBackgroundColor(ContextCompat.getColor(this, R.color.brand_200)) - selectedTitleTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) - selectedDescriptionTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) - selectedButton.setBackgroundResource(R.drawable.layout_rounded_bg_gray_alpha) - updateButtonBackgrounds(rogueButton, getDrawable(R.drawable.layout_rounded_bg_brand_700_brand_border)) + binding.selectedDescriptionTextView.text = getString(R.string.rogue_description) + binding.selectedWrapperView.setBackgroundColor(ContextCompat.getColor(this, R.color.brand_200)) + binding.selectedTitleTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) + binding.selectedDescriptionTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) + binding.selectedButton.setBackgroundResource(R.drawable.layout_rounded_bg_gray_alpha) + updateButtonBackgrounds(binding.rogueButton, ContextCompat.getDrawable(this,R.drawable.layout_rounded_bg_window_brand_border)) } private fun warriorSelected() { className = getString(R.string.warrior) - selectedDescriptionTextView.text = getString(R.string.warrior_description) - selectedWrapperView.setBackgroundColor(ContextCompat.getColor(this, R.color.maroon_50)) - selectedTitleTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) - selectedDescriptionTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) - selectedButton.setBackgroundResource(R.drawable.layout_rounded_bg_gray_alpha) - updateButtonBackgrounds(warriorButton, getDrawable(R.drawable.layout_rounded_bg_brand_700_red_border)) + binding.selectedDescriptionTextView.text = getString(R.string.warrior_description) + binding.selectedWrapperView.setBackgroundColor(ContextCompat.getColor(this, R.color.maroon_50)) + binding.selectedTitleTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) + binding.selectedDescriptionTextView.setTextColor(ContextCompat.getColor(this, R.color.white)) + binding.selectedButton.setBackgroundResource(R.drawable.layout_rounded_bg_gray_alpha) + updateButtonBackgrounds(binding.warriorButton, ContextCompat.getDrawable(this,R.drawable.layout_rounded_bg_window_red_border)) } private fun updateButtonBackgrounds(selectedButton: TextView, background: Drawable?) { - val deselectedBackground = getDrawable(R.drawable.layout_rounded_bg_gray_700) - healerButton.background = if (healerButton == selectedButton) background else deselectedBackground - mageButton.background = if (mageButton == selectedButton) background else deselectedBackground - rogueButton.background = if (rogueButton == selectedButton) background else deselectedBackground - warriorButton.background = if (warriorButton == selectedButton) background else deselectedBackground + val deselectedBackground = ContextCompat.getDrawable(this, R.drawable.layout_rounded_bg_window) + binding.healerButton.background = if (binding.healerButton == selectedButton) background else deselectedBackground + binding.mageButton.background = if (binding.mageButton == selectedButton) background else deselectedBackground + binding.rogueButton.background = if (binding.rogueButton == selectedButton) background else deselectedBackground + binding.warriorButton.background = if (binding.warriorButton == selectedButton) background else deselectedBackground } private fun optOutSelected() { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FixCharacterValuesActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FixCharacterValuesActivity.kt index dbd66a8b1..a803f0c4e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FixCharacterValuesActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FixCharacterValuesActivity.kt @@ -12,14 +12,12 @@ import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.databinding.ActivityFixcharacterBinding +import com.habitrpg.android.habitica.extensions.setTintWith import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper -import io.reactivex.functions.Action -import io.reactivex.functions.Consumer -import kotlinx.android.synthetic.main.activity_fixcharacter.* import javax.inject.Inject import javax.inject.Named @@ -49,7 +47,7 @@ class FixCharacterValuesActivity: BaseActivity() { setTitle(R.string.fix_character_values) setupToolbar(binding.toolbar) - compositeSubscription.add(repository.getUser(userId).firstElement().subscribe(Consumer { + compositeSubscription.add(repository.getUser(userId).firstElement().subscribe({ user = it }, RxErrorHandler.handleEmptyError())) @@ -57,7 +55,7 @@ class FixCharacterValuesActivity: BaseActivity() { setIconBackground(binding.experienceIconBackgroundView, ContextCompat.getColor(this, R.color.yellow_500)) setIconBackground(binding.manaIconBackgroundView, ContextCompat.getColor(this, R.color.blue_500)) setIconBackground(binding.goldIconBackgroundView, ContextCompat.getColor(this, R.color.yellow_500)) - setIconBackground(binding.streakIconBackgroundView, ContextCompat.getColor(this, R.color.gray_400)) + setIconBackground(binding.streakIconBackgroundView, ContextCompat.getColor(this, R.color.separator)) binding.healthIconView.setImageBitmap(HabiticaIconsHelper.imageOfHeartLightBg()) binding.experienceIconView.setImageBitmap(HabiticaIconsHelper.imageOfExperience()) @@ -85,7 +83,7 @@ class FixCharacterValuesActivity: BaseActivity() { userInfo["stats.mp"] = binding.manaEditText.getDoubleValue() userInfo["stats.lvl"] = binding.levelEditText.getDoubleValue().toInt() userInfo["achievements.streak"] = binding.streakEditText.getDoubleValue().toInt() - compositeSubscription.add(repository.updateUser(user, userInfo).subscribe(Consumer {}, RxErrorHandler.handleEmptyError(), Action { + compositeSubscription.add(repository.updateUser(user, userInfo).subscribe({}, RxErrorHandler.handleEmptyError(), { progressDialog.dismiss() finish() })) @@ -114,19 +112,19 @@ class FixCharacterValuesActivity: BaseActivity() { when (stats.habitClass) { Stats.WARRIOR -> { - setIconBackground(levelIconBackgroundView, ContextCompat.getColor(this, R.color.red_500)) + setIconBackground(binding.levelIconBackgroundView, ContextCompat.getColor(this, R.color.red_500)) binding.levelIconView.setImageBitmap(HabiticaIconsHelper.imageOfWarriorLightBg()) } Stats.MAGE -> { - setIconBackground(levelIconBackgroundView, ContextCompat.getColor(this, R.color.blue_500)) + setIconBackground(binding.levelIconBackgroundView, ContextCompat.getColor(this, R.color.blue_500)) binding.levelIconView.setImageBitmap(HabiticaIconsHelper.imageOfMageLightBg()) } Stats.HEALER -> { - setIconBackground(levelIconBackgroundView, ContextCompat.getColor(this, R.color.yellow_500)) + setIconBackground(binding.levelIconBackgroundView, ContextCompat.getColor(this, R.color.yellow_500)) binding.levelIconView.setImageBitmap(HabiticaIconsHelper.imageOfHealerLightBg()) } Stats.ROGUE -> { - setIconBackground(levelIconBackgroundView, ContextCompat.getColor(this, R.color.brand_500)) + setIconBackground(binding.levelIconBackgroundView, ContextCompat.getColor(this, R.color.brand_500)) binding.levelIconView.setImageBitmap(HabiticaIconsHelper.imageOfRogueLightBg()) } } @@ -134,7 +132,7 @@ class FixCharacterValuesActivity: BaseActivity() { private fun setIconBackground(view: View, color: Int) { val backgroundDrawable = ContextCompat.getDrawable(this, R.drawable.layout_rounded_bg) - backgroundDrawable?.setColorFilter(color, PorterDuff.Mode.MULTIPLY) + backgroundDrawable?.setTintWith(color, PorterDuff.Mode.MULTIPLY) backgroundDrawable?.alpha = 50 view.background = backgroundDrawable } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt index 369475c96..c08f376d1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/FullProfileActivity.kt @@ -4,12 +4,13 @@ import android.content.Context import android.graphics.Typeface import android.os.Bundle import android.view.* -import android.widget.* -import androidx.appcompat.widget.AppCompatImageView +import android.widget.ProgressBar +import android.widget.TableLayout +import android.widget.TableRow +import android.widget.TextView import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.core.os.bundleOf -import androidx.core.widget.NestedScrollView import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.controller.BaseControllerListener import com.facebook.drawee.view.SimpleDraweeView @@ -21,6 +22,7 @@ import com.habitrpg.android.habitica.data.InventoryRepository import com.habitrpg.android.habitica.data.SocialRepository import com.habitrpg.android.habitica.data.UserRepository import com.habitrpg.android.habitica.databinding.ActivityFullProfileBinding +import com.habitrpg.android.habitica.extensions.addCancelButton import com.habitrpg.android.habitica.helpers.MainNavigationController import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.helpers.UserStatComputer @@ -32,7 +34,7 @@ import com.habitrpg.android.habitica.models.user.Stats import com.habitrpg.android.habitica.ui.AvatarView import com.habitrpg.android.habitica.ui.AvatarWithBarsViewModel import com.habitrpg.android.habitica.ui.adapter.social.AchievementProfileAdapter -import com.habitrpg.android.habitica.ui.helpers.bindView +import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard import com.habitrpg.android.habitica.ui.helpers.loadImage import com.habitrpg.android.habitica.ui.helpers.setMarkdown @@ -40,7 +42,6 @@ import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.SnackbarDisplayType import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.Flowable -import io.reactivex.functions.Consumer import io.realm.RealmResults import net.pherth.android.emoji_library.EmojiEditText import java.text.SimpleDateFormat @@ -50,6 +51,8 @@ import kotlin.math.floor import kotlin.math.min class FullProfileActivity : BaseActivity() { + private var blocks: List = listOf() + @Inject lateinit var inventoryRepository: InventoryRepository @Inject @@ -59,30 +62,6 @@ class FullProfileActivity : BaseActivity() { @Inject lateinit var userRepository: UserRepository - private val toolbar: Toolbar by bindView(R.id.toolbar) - private val profileImage: SimpleDraweeView by bindView(R.id.profile_image) - private val blurbTextView: TextView by bindView(R.id.profile_blurb) - private val attributesCardView: androidx.cardview.widget.CardView by bindView(R.id.profile_attributes_card) - private val attributesTableLayout: TableLayout by bindView(R.id.attributes_table) - private val attributesCollapseIcon: AppCompatImageView by bindView(R.id.attributes_collapse_icon) - private val equipmentTableLayout: TableLayout by bindView(R.id.equipment_table) - private val costumeTableLayout: TableLayout by bindView(R.id.costume_table) - private val costumeCard: androidx.cardview.widget.CardView by bindView(R.id.profile_costume_card) - private val scrollView: NestedScrollView by bindView(R.id.fullprofile_scrollview) - private val petsFoundCount: TextView by bindView(R.id.profile_pets_found_count) - private val mountsTamedCount: TextView by bindView(R.id.profile_mounts_tamed_count) - private val currentPetDrawee: SimpleDraweeView by bindView(R.id.current_pet_drawee) - private val currentMountDrawee: SimpleDraweeView by bindView(R.id.current_mount_drawee) - private val achievementCard: androidx.cardview.widget.CardView by bindView(R.id.profile_achievements_card) - private val achievementProgress: ProgressBar by bindView(R.id.avatar_achievements_progress) - private val achievementGroupList: androidx.recyclerview.widget.RecyclerView by bindView(R.id.recyclerView) - private val joinedView: TextView by bindView(R.id.joined_view) - private val lastLoginView: TextView by bindView(R.id.last_login_view) - private val totalCheckinsView: TextView by bindView(R.id.total_checkins_view) - private val sendMessageButton: Button by bindView(R.id.send_message_button) - private val giftGemsButton: Button by bindView(R.id.gift_gems_button) - private val giftSubscriptionButton: Button by bindView(R.id.gift_subscription_button) - private var userID = "" private var username: String? = null private var userDisplayName: String? = null @@ -94,11 +73,12 @@ class FullProfileActivity : BaseActivity() { private val attributeRows = ArrayList () private val dateFormatter = SimpleDateFormat.getDateInstance() private var avatarWithBars: AvatarWithBarsViewModel? = null - lateinit private var binding: ActivityFullProfileBinding + private lateinit var binding: ActivityFullProfileBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setupToolbar(toolbar) + setupToolbar(binding.toolbar) userID = intent?.extras?.getString("userID", "") ?: "" if (userID.isEmpty()) { @@ -107,18 +87,20 @@ class FullProfileActivity : BaseActivity() { setTitle(R.string.profile_loading_data) - compositeSubscription.add(socialRepository.getMember(this.userID).subscribe(Consumer { this.updateView(it) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(socialRepository.getMember(this.userID).subscribe({ this.updateView(it) }, RxErrorHandler.handleEmptyError())) avatarWithBars = AvatarWithBarsViewModel(this, binding.avatarWithBars) - avatarWithBars?.valueBarLabelsToBlack() binding.avatarWithBars.root.setBackgroundColor(ContextCompat.getColor(this, R.color.transparent)) attributeRows.clear() - attributesCardView.setOnClickListener { toggleAttributeDetails() } + binding.attributesCardView.setOnClickListener { toggleAttributeDetails() } - sendMessageButton.setOnClickListener { showSendMessageToUserDialog() } - giftGemsButton.setOnClickListener { MainNavigationController.navigate(R.id.giftGemsActivity, bundleOf(Pair("userID", userID), Pair("username", null))) } - giftSubscriptionButton.setOnClickListener { MainNavigationController.navigate(R.id.giftSubscriptionActivity, bundleOf(Pair("userID", userID), Pair("username", null))) } + binding.sendMessageButton.setOnClickListener { showSendMessageToUserDialog() } + binding.giftGemsButton.setOnClickListener { MainNavigationController.navigate(R.id.giftGemsActivity, bundleOf(Pair("userID", userID), Pair("username", null))) } + binding.giftSubscriptionButton.setOnClickListener { MainNavigationController.navigate(R.id.giftSubscriptionActivity, bundleOf(Pair("userID", userID), Pair("username", null))) } + compositeSubscription.add(userRepository.getUser().subscribe({ + blocks = it.inbox?.blocks ?: listOf() + }, RxErrorHandler.handleEmptyError())) } override fun onDestroy() { @@ -129,35 +111,69 @@ class FullProfileActivity : BaseActivity() { override fun onCreateOptionsMenu(menu: Menu?): Boolean { val inflater = menuInflater inflater.inflate(R.menu.menu_full_profile, menu) + val item = menu?.findItem(R.id.block_user) + if (blocks.contains(userID)) { + item?.title = getString(R.string.unblock_user) + } else { + item?.title = getString(R.string.block) + } + findViewById (R.id.toolbar).let { ToolbarColorHelper.colorizeToolbar(it, this, overrideModernHeader) } return super.onCreateOptionsMenu(menu) } override fun onOptionsItemSelected(item: MenuItem): Boolean { - return when { - item.itemId == android.R.id.home -> { + return when (item.itemId) { + android.R.id.home -> { finish() true } - item.itemId == R.id.copy_username -> { + R.id.copy_username -> { val clipboard = this.getSystemService(Context.CLIPBOARD_SERVICE) as? android.content.ClipboardManager val clip = android.content.ClipData.newPlainText(username, username) clipboard?.setPrimaryClip(clip) - HabiticaSnackbar.showSnackbar(this@FullProfileActivity.scrollView.getChildAt(0) as ViewGroup, + HabiticaSnackbar.showSnackbar(this@FullProfileActivity.binding.scrollView.getChildAt(0) as ViewGroup, String.format(getString(R.string.username_copied), userDisplayName), SnackbarDisplayType.NORMAL) true } - item.itemId == R.id.copy_userid -> { + R.id.copy_userid -> { val clipboard = this.getSystemService(Context.CLIPBOARD_SERVICE) as? android.content.ClipboardManager val clip = android.content.ClipData.newPlainText(userID, userID) clipboard?.setPrimaryClip(clip) - HabiticaSnackbar.showSnackbar(this@FullProfileActivity.scrollView.getChildAt(0) as ViewGroup, + HabiticaSnackbar.showSnackbar(this@FullProfileActivity.binding.scrollView.getChildAt(0) as ViewGroup, String.format(getString(R.string.id_copied), userDisplayName), SnackbarDisplayType.NORMAL) true } + R.id.block_user -> { + if (blocks.contains(userID)) { + useBlock() + } else { + showBlockDialog() + } + true + } else -> super.onOptionsItemSelected(item) } } + private fun useBlock() { + compositeSubscription.add(socialRepository.blockMember(userID).flatMap { + userRepository.retrieveUser() + }.subscribe({ + invalidateOptionsMenu() + }, RxErrorHandler.handleEmptyError())) + } + + private fun showBlockDialog() { + val dialog = HabiticaAlertDialog(this) + dialog.setTitle(getString(R.string.block_user_title, userDisplayName)) + dialog.setMessage(R.string.block_user_description) + dialog.addButton(R.string.block, true, true) { _, _ -> + useBlock() + } + dialog.addCancelButton() + dialog.show() + } + private fun showSendMessageToUserDialog() { val factory = LayoutInflater.from(this) val newMessageView = factory.inflate(R.layout.profile_new_message_dialog, null) @@ -170,8 +186,8 @@ class FullProfileActivity : BaseActivity() { val addMessageDialog = HabiticaAlertDialog(this) addMessageDialog.addButton(android.R.string.ok, true) { _, _ -> socialRepository.postPrivateMessage(userID, emojiEditText.text.toString()) - .subscribe(Consumer { - HabiticaSnackbar.showSnackbar(this@FullProfileActivity.scrollView.getChildAt(0) as ViewGroup, + .subscribe({ + HabiticaSnackbar.showSnackbar(this@FullProfileActivity.binding.scrollView.getChildAt(0) as ViewGroup, String.format(getString(R.string.profile_message_sent_to), userDisplayName), SnackbarDisplayType.NORMAL) }, RxErrorHandler.handleEmptyError()) @@ -193,13 +209,13 @@ class FullProfileActivity : BaseActivity() { val imageUrl = profile.imageUrl if (imageUrl == null || imageUrl.isEmpty()) { - profileImage.visibility = View.GONE + binding.profileImage.visibility = View.GONE } else { - profileImage.controller = Fresco.newDraweeControllerBuilder() + binding.profileImage.controller = Fresco.newDraweeControllerBuilder() .setUri(imageUrl) .setControllerListener(object : BaseControllerListener () { override fun onFailure(id: String?, throwable: Throwable?) { - profileImage.visibility = View.GONE + binding.profileImage.visibility = View.GONE } }) .build() @@ -207,34 +223,34 @@ class FullProfileActivity : BaseActivity() { val blurbText = profile.blurb if (blurbText != null && blurbText.isNotEmpty()) { - blurbTextView.setMarkdown(blurbText) + binding.blurbTextView.setMarkdown(blurbText) } - user.authentication?.timestamps?.createdAt?.let { joinedView.text = dateFormatter.format(it) } - user.authentication?.timestamps?.lastLoggedIn?.let { lastLoginView.text = dateFormatter.format(it) } - totalCheckinsView.text = user.loginIncentives.toString() + user.authentication?.timestamps?.createdAt?.let { binding.joinedView.text = dateFormatter.format(it) } + user.authentication?.timestamps?.lastLoggedIn?.let { binding.lastLoginView.text = dateFormatter.format(it) } + binding.totalCheckinsView.text = user.loginIncentives.toString() avatarWithBars?.updateData(user) - compositeSubscription.add(loadItemDataByOutfit(user.equipped).subscribe(Consumer { gear -> this.gotGear(gear, user) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(loadItemDataByOutfit(user.equipped).subscribe({ gear -> this.gotGear(gear, user) }, RxErrorHandler.handleEmptyError())) if (user.preferences?.costume == true) { - compositeSubscription.add(loadItemDataByOutfit(user.costume).subscribe(Consumer > { this.gotCostume(it) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(loadItemDataByOutfit(user.costume).subscribe({ this.gotCostume(it) }, RxErrorHandler.handleEmptyError())) } else { - costumeCard.visibility = View.GONE + binding.costumeCard.visibility = View.GONE } // Load the members achievements now - compositeSubscription.add(socialRepository.getMemberAchievements(this.userID).subscribe(Consumer { this.fillAchievements(it) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(socialRepository.getMemberAchievements(this.userID).subscribe({ this.fillAchievements(it) }, RxErrorHandler.handleEmptyError())) } private fun updatePetsMountsView(user: Member) { - petsFoundCount.text = user.petsFoundCount.toString() - mountsTamedCount.text = user.mountsTamedCount.toString() + binding.petsFoundCount.text = user.petsFoundCount.toString() + binding.mountsTamedCount.text = user.mountsTamedCount.toString() - currentPetDrawee.loadImage("Pet-" + user.currentPet) - currentMountDrawee.loadImage("Mount_Icon_" + user.currentMount) + binding.currentPetDrawee.loadImage("Pet-" + user.currentPet) + binding.currentMountDrawee.loadImage("Mount_Icon_" + user.currentMount) } // endregion @@ -264,16 +280,16 @@ class FullProfileActivity : BaseActivity() { } } } - achievementGroupList.layoutManager = layoutManager - achievementGroupList.adapter = adapter + binding.achievementGroupList.layoutManager = layoutManager + binding.achievementGroupList.adapter = adapter - stopAndHideProgress(achievementProgress) + stopAndHideProgress(binding.achievementProgress) } private fun fillAchievements(labelID: Int, achievements: List , targetList: MutableList ) { // Order by ID first val achievementList = ArrayList(achievements) - achievementList.sortWith(Comparator { achievement, t1 -> achievement.index.toDouble().compareTo(t1.index.toDouble()) }) + achievementList.sortWith { achievement, t1 -> achievement.index.toDouble().compareTo(t1.index.toDouble()) } targetList.add(getString(labelID)) targetList.addAll(achievementList) @@ -358,16 +374,16 @@ class FullProfileActivity : BaseActivity() { val userStatComputer = UserStatComputer() val statsRows = userStatComputer.computeClassBonus(equipmentList, user) - equipmentTableLayout.removeAllViews() - for (index in 1 until attributesTableLayout.childCount) { - attributesTableLayout.removeViewAt(index) + binding.equipmentTableLayout.removeAllViews() + for (index in 1 until binding.attributesTableLayout.childCount) { + binding.attributesTableLayout.removeViewAt(index) } addLevelAttributes(user) for (row in statsRows) { if (row is UserStatComputer.EquipmentRow) { - addEquipmentRow(equipmentTableLayout, row.gearKey, row.text, row.stats) + addEquipmentRow(binding.equipmentTableLayout, row.gearKey, row.text, row.stats) } else if (row is UserStatComputer.AttributeRow) { addAttributeRow(getString(row.labelId), row.strVal, row.intVal, row.conVal, row.perVal, row.roundDown, row.summary) } @@ -378,9 +394,9 @@ class FullProfileActivity : BaseActivity() { private fun gotCostume(obj: List ) { // fill costume table - costumeTableLayout.removeAllViews() + binding.costumeTableLayout.removeAllViews() for (i in obj) { - addEquipmentRow(costumeTableLayout, i.key, i.text, "") + addEquipmentRow(binding.costumeTableLayout, i.key, i.text, "") } } @@ -388,14 +404,15 @@ class FullProfileActivity : BaseActivity() { val buffs = stats.buffs addAttributeRow(getString(R.string.profile_allocated), stats.strength?.toFloat() ?: 0f, stats.intelligence?.toFloat() ?: 0f, stats.constitution?.toFloat() ?: 0f, stats.per?.toFloat() ?: 0f, true, false) - addAttributeRow(getString(R.string.buffs), buffs?.getStr() ?: 0f, buffs?.get_int() ?: 0f, buffs?.getCon() ?: 0f, buffs?.getPer() ?: 0f, roundDown = true, isSummary = false) + addAttributeRow(getString(R.string.buffs), buffs?.str + ?: 0f, buffs?._int ?: 0f, buffs?.con ?: 0f, buffs?.per ?: 0f, roundDown = true, isSummary = false) // Summary row addAttributeRow("", attributeStrSum, attributeIntSum, attributeConSum, attributePerSum, roundDown = false, isSummary = true) } private fun addAttributeRow(label: String, strVal: Float, intVal: Float, conVal: Float, perVal: Float, roundDown: Boolean, isSummary: Boolean) { - val tableRow = layoutInflater.inflate(R.layout.profile_attributetablerow, attributesTableLayout, false) as? TableRow ?: return + val tableRow = layoutInflater.inflate(R.layout.profile_attributetablerow, binding.attributesTableLayout, false) as? TableRow ?: return val keyTextView = tableRow.findViewById (R.id.tv_attribute_type) keyTextView?.text = label @@ -426,14 +443,14 @@ class FullProfileActivity : BaseActivity() { tableRow.visibility = if (attributeDetailsHidden) View.GONE else View.VISIBLE } - attributesTableLayout.addView(tableRow) + binding.attributesTableLayout.addView(tableRow) } private fun toggleAttributeDetails() { attributeDetailsHidden = !attributeDetailsHidden - attributesCollapseIcon.setImageDrawable(ContextCompat.getDrawable(this, if (attributeDetailsHidden) + binding.attributesCollapseIcon.setImageDrawable(ContextCompat.getDrawable(this, if (attributeDetailsHidden) R.drawable.ic_keyboard_arrow_right_black_24dp else R.drawable.ic_keyboard_arrow_down_black_24dp)) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt index fccf00917..a7de2a8f1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt @@ -15,7 +15,6 @@ import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.proxy.CrashlyticsProxy import com.habitrpg.android.habitica.ui.fragments.purchases.GemsPurchaseFragment import com.habitrpg.android.habitica.ui.fragments.purchases.SubscriptionFragment -import io.reactivex.functions.Consumer import org.greenrobot.eventbus.Subscribe import javax.inject.Inject @@ -27,7 +26,6 @@ class GemPurchaseActivity : BaseActivity() { lateinit var userRepository: UserRepository internal var fragment: CheckoutFragment? = null - var isActive = false var purchaseHandler: PurchaseHandler? = null override fun getLayoutResId(): Int { @@ -75,16 +73,6 @@ class GemPurchaseActivity : BaseActivity() { purchaseHandler?.startListening() } - override fun onResume() { - super.onResume() - isActive = true - } - - override fun onPause() { - super.onPause() - isActive = false - } - public override fun onStop() { purchaseHandler?.stopListening() super.onStop() @@ -114,9 +102,9 @@ class GemPurchaseActivity : BaseActivity() { @Subscribe fun onConsumablePurchased(event: ConsumablePurchasedEvent) { - if (isActive) { + if (isActivityVisible) { purchaseHandler?.consumePurchase(event.purchase) - compositeSubscription.add(userRepository.retrieveUser(false).subscribe(Consumer {}, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(userRepository.retrieveUser(false).subscribe({}, RxErrorHandler.handleEmptyError())) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftGemsActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftGemsActivity.kt index 36a6883ca..d6b180ef7 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftGemsActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftGemsActivity.kt @@ -3,15 +3,14 @@ package com.habitrpg.android.habitica.ui.activities import android.content.Intent import android.os.Bundle import android.view.MenuItem -import androidx.appcompat.widget.Toolbar +import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentPagerAdapter import androidx.navigation.navArgs -import androidx.viewpager.widget.ViewPager -import com.google.android.material.tabs.TabLayout import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.SocialRepository +import com.habitrpg.android.habitica.databinding.ActivityGiftGemsBinding import com.habitrpg.android.habitica.events.ConsumablePurchasedEvent import com.habitrpg.android.habitica.extensions.addOkButton import com.habitrpg.android.habitica.helpers.AppConfigManager @@ -20,14 +19,14 @@ import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.proxy.CrashlyticsProxy import com.habitrpg.android.habitica.ui.fragments.purchases.GiftBalanceGemsFragment import com.habitrpg.android.habitica.ui.fragments.purchases.GiftPurchaseGemsFragment -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog -import io.reactivex.functions.Consumer import org.greenrobot.eventbus.Subscribe import javax.inject.Inject class GiftGemsActivity : BaseActivity() { + private lateinit var binding: ActivityGiftGemsBinding + @Inject lateinit var crashlyticsProxy: CrashlyticsProxy @Inject @@ -37,9 +36,6 @@ class GiftGemsActivity : BaseActivity() { private var purchaseHandler: PurchaseHandler? = null - private val toolbar: Toolbar by bindView(R.id.toolbar) - internal val tabLayout: TabLayout by bindView(R.id.tab_layout) - internal val viewPager: ViewPager by bindView(R.id.viewPager) private var giftedUsername: String? = null private var giftedUserID: String? = null @@ -51,6 +47,11 @@ class GiftGemsActivity : BaseActivity() { return R.layout.activity_gift_gems } + override fun getContentView(): View { + binding = ActivityGiftGemsBinding.inflate(layoutInflater) + return binding.root + } + override fun injectActivity(component: UserComponent?) { component?.inject(this) } @@ -59,7 +60,7 @@ class GiftGemsActivity : BaseActivity() { super.onCreate(savedInstanceState) setTitle(R.string.gift_gems) - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) purchaseHandler = PurchaseHandler(this, crashlyticsProxy) @@ -75,7 +76,7 @@ class GiftGemsActivity : BaseActivity() { setViewPagerAdapter() - compositeSubscription.add(socialRepository.getMember(giftedUsername ?: giftedUserID).firstElement().subscribe(Consumer { + compositeSubscription.add(socialRepository.getMember(giftedUsername ?: giftedUserID).firstElement().subscribe({ giftedUserID = it.id giftedUsername = it.username purchaseFragment?.giftedMember = it @@ -109,7 +110,7 @@ class GiftGemsActivity : BaseActivity() { private fun setViewPagerAdapter() { val fragmentManager = supportFragmentManager - viewPager.adapter = object : FragmentPagerAdapter(fragmentManager) { + binding.viewPager.adapter = object : FragmentPagerAdapter(fragmentManager) { override fun getItem(position: Int): Fragment { return if (position == 0) { @@ -141,7 +142,7 @@ class GiftGemsActivity : BaseActivity() { } } - tabLayout.setupWithViewPager(viewPager) + binding.tabLayout.setupWithViewPager(binding.viewPager) } @Subscribe diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftSubscriptionActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftSubscriptionActivity.kt index bd0aeeb48..fab336154 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftSubscriptionActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GiftSubscriptionActivity.kt @@ -4,16 +4,13 @@ import android.content.Intent import android.os.Bundle import android.view.MenuItem import android.view.View -import android.view.ViewGroup -import android.widget.Button -import android.widget.TextView -import androidx.appcompat.widget.Toolbar import androidx.core.view.isVisible import androidx.navigation.navArgs import com.habitrpg.android.habitica.HabiticaPurchaseVerifier import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.SocialRepository +import com.habitrpg.android.habitica.databinding.ActivityGiftSubscriptionBinding import com.habitrpg.android.habitica.events.ConsumablePurchasedEvent import com.habitrpg.android.habitica.extensions.addOkButton import com.habitrpg.android.habitica.helpers.AppConfigManager @@ -21,13 +18,8 @@ import com.habitrpg.android.habitica.helpers.PurchaseHandler import com.habitrpg.android.habitica.helpers.PurchaseTypes import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.proxy.CrashlyticsProxy -import com.habitrpg.android.habitica.ui.AvatarView -import com.habitrpg.android.habitica.ui.helpers.bindOptionalView -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog -import com.habitrpg.android.habitica.ui.views.social.UsernameLabel import com.habitrpg.android.habitica.ui.views.subscriptions.SubscriptionOptionView -import io.reactivex.functions.Consumer import org.greenrobot.eventbus.Subscribe import org.solovyev.android.checkout.Inventory import org.solovyev.android.checkout.Sku @@ -36,6 +28,8 @@ import javax.inject.Inject class GiftSubscriptionActivity : BaseActivity() { + private lateinit var binding: ActivityGiftSubscriptionBinding + @Inject lateinit var crashlyticsProxy: CrashlyticsProxy @Inject @@ -45,21 +39,6 @@ class GiftSubscriptionActivity : BaseActivity() { private var purchaseHandler: PurchaseHandler? = null - private val toolbar: Toolbar by bindView(R.id.toolbar) - - private val giftOneGetOneContainer: ViewGroup? by bindView(R.id.gift_subscription_container) - - private val avatarView: AvatarView by bindView(R.id.avatar_view) - private val displayNameTextView: UsernameLabel by bindView(R.id.display_name_textview) - private val usernameTextView: TextView by bindView(R.id.username_textview) - - private val subscription1MonthView: SubscriptionOptionView? by bindView(R.id.subscription1month) - private val subscription3MonthView: SubscriptionOptionView? by bindView(R.id.subscription3month) - private val subscription6MonthView: SubscriptionOptionView? by bindView(R.id.subscription6month) - private val subscription12MonthView: SubscriptionOptionView? by bindView(R.id.subscription12month) - - private val subscriptionButton: Button? by bindOptionalView(R.id.subscribeButton) - private var giftedUsername: String? = null private var giftedUserID: String? = null @@ -74,11 +53,16 @@ class GiftSubscriptionActivity : BaseActivity() { component?.inject(this) } + override fun getContentView(): View { + binding = ActivityGiftSubscriptionBinding.inflate(layoutInflater) + return binding.root + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setTitle(R.string.gift_subscription) - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true) @@ -90,17 +74,17 @@ class GiftSubscriptionActivity : BaseActivity() { giftedUsername = navArgs ().value.username } - subscriptionButton?.setOnClickListener { + binding.subscriptionButton.setOnClickListener { selectedSubscriptionSku?.let { sku -> purchaseSubscription(sku) } } - giftOneGetOneContainer?.isVisible = appConfigManager.enableGiftOneGetOne() + binding.giftSubscriptionContainer.isVisible = appConfigManager.enableGiftOneGetOne() - compositeSubscription.add(socialRepository.getMember(giftedUsername ?: giftedUserID).subscribe(Consumer { - avatarView.setAvatar(it) - displayNameTextView.username = it.profile?.name - displayNameTextView.tier = it.contributor?.level ?: 0 - usernameTextView.text = "@${it.username}" + compositeSubscription.add(socialRepository.getMember(giftedUsername ?: giftedUserID).subscribe({ + binding.avatarView.setAvatar(it) + binding.displayNameTextView.username = it.profile?.name + binding.displayNameTextView.tier = it.contributor?.level ?: 0 + binding.usernameTextView.text = "@${it.username}" giftedUserID = it.id giftedUsername = it.username }, RxErrorHandler.handleEmptyError())) @@ -122,10 +106,10 @@ class GiftSubscriptionActivity : BaseActivity() { override fun onResume() { super.onResume() - this.subscription1MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription1MonthNoRenew) }) - this.subscription3MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription3MonthNoRenew) }) - this.subscription6MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription6MonthNoRenew) }) - this.subscription12MonthView?.setOnPurchaseClickListener(View.OnClickListener { selectSubscription(PurchaseTypes.Subscription12MonthNoRenew) }) + binding.subscription1MonthView.setOnPurchaseClickListener { selectSubscription(PurchaseTypes.Subscription1MonthNoRenew) } + binding.subscription3MonthView.setOnPurchaseClickListener { selectSubscription(PurchaseTypes.Subscription3MonthNoRenew) } + binding.subscription6MonthView.setOnPurchaseClickListener { selectSubscription(PurchaseTypes.Subscription6MonthNoRenew) } + binding.subscription12MonthView.setOnPurchaseClickListener { selectSubscription(PurchaseTypes.Subscription12MonthNoRenew) } } override fun onStop() { @@ -171,9 +155,7 @@ class GiftSubscriptionActivity : BaseActivity() { this.selectedSubscriptionSku = sku val subscriptionOptionButton = buttonForSku(this.selectedSubscriptionSku) subscriptionOptionButton?.setIsPurchased(true) - if (this.subscriptionButton != null) { - this.subscriptionButton?.isEnabled = true - } + binding.subscriptionButton.isEnabled = true } private fun buttonForSku(sku: Sku?): SubscriptionOptionView? { @@ -182,10 +164,10 @@ class GiftSubscriptionActivity : BaseActivity() { private fun buttonForSku(sku: String?): SubscriptionOptionView? { return when (sku) { - PurchaseTypes.Subscription1MonthNoRenew -> subscription1MonthView - PurchaseTypes.Subscription3MonthNoRenew -> subscription3MonthView - PurchaseTypes.Subscription6MonthNoRenew -> subscription6MonthView - PurchaseTypes.Subscription12MonthNoRenew -> subscription12MonthView + PurchaseTypes.Subscription1MonthNoRenew -> binding.subscription1MonthView + PurchaseTypes.Subscription3MonthNoRenew -> binding.subscription3MonthView + PurchaseTypes.Subscription6MonthNoRenew -> binding.subscription6MonthView + PurchaseTypes.Subscription12MonthNoRenew -> binding.subscription12MonthView else -> null } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupFormActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupFormActivity.kt index 843b959ee..1cc20c156 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupFormActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupFormActivity.kt @@ -4,14 +4,17 @@ import android.app.Activity import android.content.Intent import android.os.Bundle import android.view.View -import android.widget.* import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent -import com.habitrpg.android.habitica.ui.helpers.* -import com.habitrpg.android.habitica.ui.views.HabiticaAutocompleteTextView +import com.habitrpg.android.habitica.databinding.ActivityGroupFormBinding +import com.habitrpg.android.habitica.ui.helpers.AutocompleteAdapter +import com.habitrpg.android.habitica.ui.helpers.AutocompleteTokenizer +import com.habitrpg.android.habitica.ui.helpers.MarkdownParser +import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard class GroupFormActivity : BaseActivity() { + private lateinit var binding: ActivityGroupFormBinding private var groupID: String? = null private var groupType: String? = null private var groupName: String? = null @@ -20,21 +23,17 @@ class GroupFormActivity : BaseActivity() { private var groupLeader: String? = null private var leaderCreateChallenge = false - private val cancelButton: ImageButton by bindView(R.id.cancel_button) - private val saveButton: Button by bindView(R.id.save_button) - private val groupNameEditText: HabiticaAutocompleteTextView by bindView(R.id.group_name_edittext) - private val groupDescriptionEditText: HabiticaAutocompleteTextView by bindView(R.id.group_description_edittext) - private val leaderCreateChallengeSwitch: Switch by bindView(R.id.leader_create_challenge_switch) - private val privacyWrapper: LinearLayout by bindView(R.id.privacyWrapper) - internal val privacySpinner: Spinner by bindView(R.id.privacySpinner) - private val privacySeparator: View by bindView(R.id.privacy_separator) - private var autocompleteAdapter: AutocompleteAdapter? = null override fun getLayoutResId(): Int { return R.layout.activity_group_form } + override fun getContentView(): View { + binding = ActivityGroupFormBinding.inflate(layoutInflater) + return binding.root + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -49,31 +48,31 @@ class GroupFormActivity : BaseActivity() { } if (groupType == "party") { - privacyWrapper.visibility = View.GONE - privacySeparator.visibility = View.GONE + binding.privacyWrapper.visibility = View.GONE + binding.privacySeparator.visibility = View.GONE } if (groupID != null) { fillForm() } - cancelButton.setOnClickListener { + binding.cancelButton.setOnClickListener { finish() dismissKeyboard() } - saveButton.setOnClickListener { + binding.saveButton.setOnClickListener { finishActivitySuccessfuly() } autocompleteAdapter = AutocompleteAdapter(this) val tokenizer = AutocompleteTokenizer(listOf(':')) - groupNameEditText.setAdapter(autocompleteAdapter) - groupNameEditText.threshold = 2 - groupNameEditText.setTokenizer(tokenizer) - groupDescriptionEditText.setAdapter(autocompleteAdapter) - groupDescriptionEditText.setTokenizer(tokenizer) - groupDescriptionEditText.threshold = 2 + binding.groupNameEditText.setAdapter(autocompleteAdapter) + binding.groupNameEditText.threshold = 2 + binding.groupNameEditText.setTokenizer(tokenizer) + binding.groupDescriptionEditText.setAdapter(autocompleteAdapter) + binding.groupDescriptionEditText.setTokenizer(tokenizer) + binding.groupDescriptionEditText.threshold = 2 } @@ -82,11 +81,11 @@ class GroupFormActivity : BaseActivity() { } private fun fillForm() { - groupNameEditText.setText(groupName) - groupDescriptionEditText.setText(groupDescription) - leaderCreateChallengeSwitch.isChecked = leaderCreateChallenge - privacyWrapper.visibility = View.GONE - saveButton.text = getString(R.string.save) + binding.groupNameEditText.setText(groupName) + binding.groupDescriptionEditText.setText(groupDescription) + binding.leaderCreateChallengeSwitch.isChecked = leaderCreateChallenge + binding.privacyWrapper.visibility = View.GONE + binding.saveButton.text = getString(R.string.save) } override fun onSupportNavigateUp(): Boolean { @@ -101,7 +100,7 @@ class GroupFormActivity : BaseActivity() { } private fun finishActivitySuccessfuly() { - val name = groupNameEditText.text.toString() + val name = binding.groupNameEditText.text.toString() if (name.isEmpty()) { return } @@ -109,8 +108,8 @@ class GroupFormActivity : BaseActivity() { val bundle = Bundle() bundle.putString("name", name) bundle.putString("groupType", groupType) - bundle.putString("description", MarkdownParser.parseCompiled(this.groupDescriptionEditText.text)) - bundle.putBoolean("leaderOnlyChallenges", leaderCreateChallengeSwitch.isChecked) + bundle.putString("description", MarkdownParser.parseCompiled(binding.groupDescriptionEditText.text)) + bundle.putBoolean("leaderOnlyChallenges", binding.leaderCreateChallengeSwitch.isChecked) bundle.putString("leader", this.groupLeader) resultIntent.putExtras(bundle) setResult(Activity.RESULT_OK, resultIntent) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupInviteActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupInviteActivity.kt index 5f390b3fb..8f6322ce6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupInviteActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GroupInviteActivity.kt @@ -5,34 +5,32 @@ import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem -import android.view.ViewGroup +import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentPagerAdapter -import androidx.viewpager.widget.ViewPager -import com.google.android.material.tabs.TabLayout import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.SocialRepository import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.databinding.ActivityPartyInviteBinding import com.habitrpg.android.habitica.extensions.runDelayed import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.fragments.social.party.PartyInviteFragment -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar.Companion.showSnackbar -import io.reactivex.functions.Consumer import java.util.* import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Named - class GroupInviteActivity : BaseActivity() { + private lateinit var binding: ActivityPartyInviteBinding + @field:[Inject Named(AppModule.NAMED_USER_ID)] lateinit var userId: String @Inject @@ -40,10 +38,6 @@ class GroupInviteActivity : BaseActivity() { @Inject lateinit var userRepository: UserRepository - internal val tabLayout: TabLayout by bindView(R.id.tab_layout) - internal val viewPager: ViewPager by bindView(R.id.viewPager) - private val snackbarView: ViewGroup by bindView(R.id.snackbar_view) - internal var fragments: MutableList = ArrayList() private var userIdToInvite: String? = null @@ -51,10 +45,15 @@ class GroupInviteActivity : BaseActivity() { return R.layout.activity_party_invite } + override fun getContentView(): View { + binding = ActivityPartyInviteBinding.inflate(layoutInflater) + return binding.root + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setupToolbar(findViewById(R.id.toolbar)) - viewPager.currentItem = 0 + binding.viewPager.currentItem = 0 supportActionBar?.title = null @@ -66,7 +65,6 @@ class GroupInviteActivity : BaseActivity() { } override fun onCreateOptionsMenu(menu: Menu): Boolean { - // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.menu_party_invite, menu) return true } @@ -77,8 +75,8 @@ class GroupInviteActivity : BaseActivity() { R.id.action_send_invites -> { setResult(Activity.RESULT_OK, createResultIntent()) dismissKeyboard() - if (fragments.size > viewPager.currentItem && fragments[viewPager.currentItem].values.isNotEmpty()) { - showSnackbar(snackbarView, "Invite Sent!", HabiticaSnackbar.SnackbarDisplayType.SUCCESS) + if (fragments.size > binding.viewPager.currentItem && fragments[binding.viewPager.currentItem].values.isNotEmpty()) { + showSnackbar(binding.snackbarView, "Invite Sent!", HabiticaSnackbar.SnackbarDisplayType.SUCCESS) runDelayed(1, TimeUnit.SECONDS, this::finish) } else { finish() @@ -96,7 +94,7 @@ class GroupInviteActivity : BaseActivity() { private fun createResultIntent(): Intent { val intent = Intent() if (fragments.size == 0) return intent - val fragment = fragments[viewPager.currentItem] + val fragment = fragments[binding.viewPager.currentItem] intent.putExtra(EMAILS_KEY, fragments[1].values) intent.putExtra(USER_IDS_KEY, fragments[0].values) return intent @@ -105,7 +103,7 @@ class GroupInviteActivity : BaseActivity() { private fun setViewPagerAdapter() { val fragmentManager = supportFragmentManager - viewPager.adapter = object : FragmentPagerAdapter(fragmentManager) { + binding.viewPager.adapter = object : FragmentPagerAdapter(fragmentManager) { override fun getItem(position: Int): Fragment { val fragment = PartyInviteFragment() @@ -132,27 +130,10 @@ class GroupInviteActivity : BaseActivity() { } } - tabLayout.setupWithViewPager(viewPager) - } - - private fun handleUserReceived(user: User) { - if (this.userIdToInvite == null) { - return - } - - val inviteData = HashMap () - val invites = ArrayList () - userIdToInvite?.let { - invites.add(it) - } - inviteData["uuids"] = invites - - compositeSubscription.add(this.socialRepository.inviteToGroup(user.party?.id ?: "", inviteData) - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError())) + binding.tabLayout.setupWithViewPager(binding.viewPager) } companion object { - const val RESULT_SEND_INVITES = 100 const val USER_IDS_KEY = "userIDs" const val IS_EMAIL_KEY = "isEmail" diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.kt index 61fba8159..04a1a3860 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.kt @@ -4,31 +4,31 @@ import android.app.Activity import android.appwidget.AppWidgetManager import android.content.Intent import android.os.Bundle +import android.view.View import androidx.core.content.edit import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.TaskRepository +import com.habitrpg.android.habitica.databinding.WidgetConfigureHabitButtonBinding import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.adapter.SkillTasksRecyclerViewAdapter -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.widget.HabitButtonWidgetProvider -import io.reactivex.functions.Consumer import javax.inject.Inject import javax.inject.Named class HabitButtonWidgetActivity : BaseActivity() { + private lateinit var binding: WidgetConfigureHabitButtonBinding + @Inject lateinit var taskRepository: TaskRepository @field:[Inject Named(AppModule.NAMED_USER_ID)] lateinit var userId: String - internal val recyclerView: RecyclerView by bindView(R.id.recyclerView) private var widgetId: Int = 0 private var adapter: SkillTasksRecyclerViewAdapter? = null @@ -36,6 +36,11 @@ class HabitButtonWidgetActivity : BaseActivity() { return R.layout.widget_configure_habit_button } + override fun getContentView(): View { + binding = WidgetConfigureHabitButtonBinding.inflate(layoutInflater) + return binding.root + } + override fun injectActivity(component: UserComponent?) { component?.inject(this) } @@ -55,21 +60,21 @@ class HabitButtonWidgetActivity : BaseActivity() { finish() } - var layoutManager: LinearLayoutManager? = recyclerView.layoutManager as? LinearLayoutManager + var layoutManager: LinearLayoutManager? = binding.recyclerView.layoutManager as? LinearLayoutManager if (layoutManager == null) { layoutManager = LinearLayoutManager(this) - recyclerView.layoutManager = layoutManager + binding.recyclerView.layoutManager = layoutManager } adapter = SkillTasksRecyclerViewAdapter(null, true) - adapter?.getTaskSelectionEvents()?.subscribe(Consumer { task -> taskSelected(task.id) }, + adapter?.getTaskSelectionEvents()?.subscribe({ task -> taskSelected(task.id) }, RxErrorHandler.handleEmptyError()) ?.let { compositeSubscription.add(it) } - recyclerView.adapter = adapter + binding.recyclerView.adapter = adapter - compositeSubscription.add(taskRepository.getTasks(Task.TYPE_HABIT, userId).firstElement().subscribe(Consumer { adapter?.updateData(it) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(taskRepository.getTasks(Task.TYPE_HABIT, userId).firstElement().subscribe({ adapter?.updateData(it) }, RxErrorHandler.handleEmptyError())) } private fun taskSelected(taskId: String?) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/IntroActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/IntroActivity.kt index ac0ad6d55..bb20834ce 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/IntroActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/IntroActivity.kt @@ -17,7 +17,6 @@ import com.habitrpg.android.habitica.databinding.ActivityIntroBinding import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.ui.fragments.setup.IntroFragment import com.viewpagerindicator.IconPagerAdapter -import io.reactivex.functions.Consumer import javax.inject.Inject @@ -40,12 +39,12 @@ class IntroActivity : BaseActivity(), View.OnClickListener, ViewPager.OnPageChan super.onCreate(savedInstanceState) setupIntro() - //binding.viewPagerIndicator.setViewPager(binding.viewPager) + binding.viewPagerIndicator.setViewPager(binding.viewPager) binding.skipButton.setOnClickListener(this) binding.finishButton.setOnClickListener(this) - compositeSubscription.add(contentRepository.retrieveContent(this).subscribe(Consumer { }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(contentRepository.retrieveContent(this).subscribe({ }, RxErrorHandler.handleEmptyError())) } override fun injectActivity(component: UserComponent?) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.kt index 05ca41dd6..7827625ff 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.kt @@ -16,7 +16,8 @@ import android.view.View import android.view.Window import android.view.WindowManager import android.view.inputmethod.EditorInfo -import android.widget.* +import android.widget.EditText +import android.widget.LinearLayout import androidx.core.content.ContextCompat import androidx.core.content.edit import androidx.preference.PreferenceManager @@ -39,17 +40,15 @@ import com.habitrpg.android.habitica.api.HostConfig import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.ApiClient import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.databinding.ActivityLoginBinding import com.habitrpg.android.habitica.extensions.addCancelButton import com.habitrpg.android.habitica.extensions.addCloseButton import com.habitrpg.android.habitica.extensions.addOkButton import com.habitrpg.android.habitica.helpers.* import com.habitrpg.android.habitica.models.auth.UserAuthResponse import com.habitrpg.android.habitica.proxy.CrashlyticsProxy -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog -import com.habitrpg.android.habitica.ui.views.login.LockableScrollView -import com.habitrpg.android.habitica.ui.views.login.LoginBackgroundView import com.willowtreeapps.signinwithapplebutton.SignInWithAppleConfiguration import io.reactivex.Flowable import io.reactivex.exceptions.Exceptions @@ -60,6 +59,8 @@ import javax.inject.Inject class LoginActivity : BaseActivity(), Consumer { + private lateinit var binding: ActivityLoginBinding + @Inject lateinit var apiClient: ApiClient @Inject @@ -79,36 +80,17 @@ class LoginActivity : BaseActivity(), Consumer { private var isRegistering: Boolean = false private var isShowingForm: Boolean = false - private val backgroundContainer: LockableScrollView by bindView(R.id.background_container) - internal val backgroundView: LoginBackgroundView by bindView(R.id.background_view) - internal val newGameButton: Button by bindView(R.id.new_game_button) - internal val showLoginButton: Button by bindView(R.id.show_login_button) - internal val scrollView: ScrollView by bindView(R.id.login_scrollview) - private val formWrapper: LinearLayout by bindView(R.id.login_linear_layout) - private val backButton: Button by bindView(R.id.back_button) - private val logoView: ImageView by bindView(R.id.logo_view) - private val mLoginNormalBtn: Button by bindView(R.id.login_btn) - private val mProgressBar: ProgressBar by bindView(R.id.PB_AsyncTask) - private val mUsernameET: EditText by bindView(R.id.username) - private val mPasswordET: EditText by bindView(R.id.password) - private val mEmail: EditText by bindView(R.id.email) - private val mConfirmPassword: EditText by bindView(R.id.confirm_password) - private val forgotPasswordButton: Button by bindView(R.id.forgot_password) - private val facebookLoginButton: Button by bindView(R.id.fb_login_button) - private val googleLoginButton: Button by bindView(R.id.google_login_button) - private val appleLoginButton: Button by bindView(R.id.apple_login_button) - private var callbackManager = CallbackManager.Factory.create() private var googleEmail: String? = null private var loginManager = LoginManager.getInstance() private val loginClick = View.OnClickListener { - mProgressBar.visibility = View.VISIBLE + binding.PBAsyncTask.visibility = View.VISIBLE if (isRegistering) { - val username: String = mUsernameET.text.toString().trim { it <= ' ' } - val email: String = mEmail.text.toString().trim { it <= ' ' } - val password: String = mPasswordET.text.toString() - val confirmPassword: String = mConfirmPassword.text.toString() + val username: String = binding.username.text.toString().trim { it <= ' ' } + val email: String = binding.email.text.toString().trim { it <= ' ' } + val password: String = binding.password.text.toString() + val confirmPassword: String = binding.confirmPassword.text.toString() if (username.isEmpty() || password.isEmpty() || email.isEmpty() || confirmPassword.isEmpty()) { showValidationError(R.string.login_validation_error_fieldsmissing) return@OnClickListener @@ -119,19 +101,19 @@ class LoginActivity : BaseActivity(), Consumer { } apiClient.registerUser(username, email, password, confirmPassword) .subscribe(this@LoginActivity, - Consumer { + { hideProgress() RxErrorHandler.reportError(it) }) } else { - val username: String = mUsernameET.text.toString().trim { it <= ' ' } - val password: String = mPasswordET.text.toString() + val username: String = binding.username.text.toString().trim { it <= ' ' } + val password: String = binding.password.text.toString() if (username.isEmpty() || password.isEmpty()) { showValidationError(R.string.login_validation_error_fieldsmissing) return@OnClickListener } apiClient.connectUser(username, password).subscribe(this@LoginActivity, - Consumer { + { hideProgress() RxErrorHandler.reportError(it) }) @@ -143,6 +125,11 @@ class LoginActivity : BaseActivity(), Consumer { return R.layout.activity_login } + override fun getContentView(): View { + binding = ActivityLoginBinding.inflate(layoutInflater) + return binding.root + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) supportActionBar?.hide() @@ -151,11 +138,11 @@ class LoginActivity : BaseActivity(), Consumer { setupFacebookLogin() - mLoginNormalBtn.setOnClickListener(loginClick) + binding.loginBtn.setOnClickListener(loginClick) - val content = SpannableString(forgotPasswordButton.text) + val content = SpannableString(binding.forgotPassword.text) content.setSpan(UnderlineSpan(), 0, content.length, 0) - forgotPasswordButton.text = content + binding.forgotPassword.text = content this.isRegistering = true @@ -163,8 +150,8 @@ class LoginActivity : BaseActivity(), Consumer { additionalData["page"] = this.javaClass.simpleName AmplitudeManager.sendEvent("navigate", AmplitudeManager.EVENT_CATEGORY_NAVIGATION, AmplitudeManager.EVENT_HITTYPE_PAGEVIEW, additionalData) - backgroundContainer.post { backgroundContainer.scrollTo(0, backgroundContainer.bottom) } - backgroundContainer.setScrollingEnabled(false) + binding.backgroundContainer.post { binding.backgroundContainer.scrollTo(0, binding.backgroundContainer.bottom) } + binding.backgroundContainer.isScrollable = false val window = window if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -172,13 +159,13 @@ class LoginActivity : BaseActivity(), Consumer { } getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) - newGameButton.setOnClickListener { newGameButtonClicked() } - showLoginButton.setOnClickListener { showLoginButtonClicked() } - backButton.setOnClickListener { backButtonClicked() } - forgotPasswordButton.setOnClickListener { onForgotPasswordClicked() } - facebookLoginButton.setOnClickListener { handleFacebookLogin() } - googleLoginButton.setOnClickListener { handleGoogleLogin() } - appleLoginButton.setOnClickListener { + binding.newGameButton.setOnClickListener { newGameButtonClicked() } + binding.showLoginButton.setOnClickListener { showLoginButtonClicked() } + binding.backButton.setOnClickListener { backButtonClicked() } + binding.forgotPassword.setOnClickListener { onForgotPasswordClicked() } + binding.fbLoginButton.setOnClickListener { handleFacebookLogin() } + binding.googleLoginButton.setOnClickListener { handleGoogleLogin() } + binding.appleLoginButton.setOnClickListener { val configuration = SignInWithAppleConfiguration( clientId = BuildConfig.APPLE_AUTH_CLIENT_ID, redirectUri = "${hostConfig.address}/api/v4/user/auth/apple", @@ -232,18 +219,18 @@ class LoginActivity : BaseActivity(), Consumer { private fun resetLayout() { if (this.isRegistering) { - if (this.mEmail.visibility == View.GONE) { - show(this.mEmail) + if (binding.email.visibility == View.GONE) { + show(binding.email) } - if (this.mConfirmPassword.visibility == View.GONE) { - show(this.mConfirmPassword) + if (binding.confirmPassword.visibility == View.GONE) { + show(binding.confirmPassword) } } else { - if (this.mEmail.visibility == View.VISIBLE) { - hide(this.mEmail) + if (binding.email.visibility == View.VISIBLE) { + hide(binding.email) } - if (this.mConfirmPassword.visibility == View.VISIBLE) { - hide(this.mConfirmPassword) + if (binding.confirmPassword.visibility == View.VISIBLE) { + hide(binding.confirmPassword) } } } @@ -269,17 +256,25 @@ class LoginActivity : BaseActivity(), Consumer { private fun setRegistering() { if (this.isRegistering) { - this.mLoginNormalBtn.text = getString(R.string.register_btn) - mUsernameET.setHint(R.string.username) - mPasswordET.imeOptions = EditorInfo.IME_ACTION_NEXT - facebookLoginButton.setText(R.string.register_btn_fb) - googleLoginButton.setText(R.string.register_btn_google) + binding.loginBtn.text = getString(R.string.register_btn) + binding.username.setHint(R.string.username) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + binding.username.setAutofillHints("newUsername") + binding.password.setAutofillHints("newPassword") + } + binding.password.imeOptions = EditorInfo.IME_ACTION_NEXT + binding.fbLoginButton.setText(R.string.register_btn_fb) + binding.googleLoginButton.setText(R.string.register_btn_google) } else { - this.mLoginNormalBtn.text = getString(R.string.login_btn) - mUsernameET.setHint(R.string.email_username) - mPasswordET.imeOptions = EditorInfo.IME_ACTION_DONE - facebookLoginButton.setText(R.string.login_btn_fb) - googleLoginButton.setText(R.string.login_btn_google) + binding.loginBtn.text = getString(R.string.login_btn) + binding.username.setHint(R.string.email_username) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + binding.username.setAutofillHints("username") + binding.password.setAutofillHints("password") + } + binding.password.imeOptions = EditorInfo.IME_ACTION_DONE + binding.fbLoginButton.setText(R.string.login_btn_fb) + binding.googleLoginButton.setText(R.string.login_btn_google) } this.resetLayout() } @@ -307,7 +302,7 @@ class LoginActivity : BaseActivity(), Consumer { val accessToken = AccessToken.getCurrentAccessToken() if (accessToken != null && accessToken.token != null) { compositeSubscription.add(apiClient.connectSocial("facebook", accessToken.userId, accessToken.token) - .subscribe(this@LoginActivity, Consumer { hideProgress() })) + .subscribe(this@LoginActivity, { hideProgress() })) } } } @@ -343,7 +338,7 @@ class LoginActivity : BaseActivity(), Consumer { private fun hideProgress() { runOnUiThread { - mProgressBar.visibility = View.GONE + binding.PBAsyncTask.visibility = View.GONE } } @@ -352,7 +347,7 @@ class LoginActivity : BaseActivity(), Consumer { } private fun showValidationError(message: String) { - mProgressBar.visibility = View.GONE + binding.PBAsyncTask.visibility = View.GONE val alert = HabiticaAlertDialog(this) alert.setTitle(R.string.login_validation_error_title) alert.setMessage(message) @@ -376,12 +371,12 @@ class LoginActivity : BaseActivity(), Consumer { } compositeSubscription.add(userRepository.retrieveUser(true) - .subscribe(Consumer { + .subscribe({ if (userAuthResponse.newUser) { this.startSetupActivity() } else { - AmplitudeManager.sendEvent("login", AmplitudeManager.EVENT_CATEGORY_BEHAVIOUR, AmplitudeManager.EVENT_HITTYPE_EVENT) this.startMainActivity() + AmplitudeManager.sendEvent("login", AmplitudeManager.EVENT_CATEGORY_BEHAVIOUR, AmplitudeManager.EVENT_HITTYPE_EVENT) } }, RxErrorHandler.handleEmptyError())) } @@ -412,7 +407,7 @@ class LoginActivity : BaseActivity(), Consumer { private fun handleGoogleLoginResult() { val scopesString = Scopes.PROFILE + " " + Scopes.EMAIL val scopes = "oauth2:$scopesString" - Flowable.defer { + compositeSubscription.add(Flowable.defer { try { @Suppress("Deprecation") return@defer Flowable.just(GoogleAuthUtil.getToken(this, googleEmail, scopes)) @@ -424,7 +419,7 @@ class LoginActivity : BaseActivity(), Consumer { } .subscribeOn(Schedulers.io()) .flatMap { token -> apiClient.connectSocial("google", googleEmail ?: "", token) } - .subscribe(this@LoginActivity, Consumer { throwable -> + .subscribe(this@LoginActivity, { throwable -> throwable.printStackTrace() hideProgress() throwable.cause?.let { @@ -433,7 +428,7 @@ class LoginActivity : BaseActivity(), Consumer { } } - }) + })) } private fun handleGoogleAuthException(e: Exception) { @@ -493,15 +488,15 @@ class LoginActivity : BaseActivity(), Consumer { private fun showForm() { isShowingForm = true - val panAnimation = ObjectAnimator.ofInt(backgroundContainer, "scrollY", 0).setDuration(1000) - val newGameAlphaAnimation = ObjectAnimator.ofFloat (newGameButton, View.ALPHA, 0.toFloat()) - val showLoginAlphaAnimation = ObjectAnimator.ofFloat (showLoginButton, View.ALPHA, 0.toFloat()) - val scaleLogoAnimation = ValueAnimator.ofInt(logoView.measuredHeight, (logoView.measuredHeight * 0.75).toInt()) + val panAnimation = ObjectAnimator.ofInt(binding.backgroundContainer, "scrollY", 0).setDuration(1000) + val newGameAlphaAnimation = ObjectAnimator.ofFloat(binding.newGameButton, View.ALPHA, 0.toFloat()) + val showLoginAlphaAnimation = ObjectAnimator.ofFloat(binding.showLoginButton, View.ALPHA, 0.toFloat()) + val scaleLogoAnimation = ValueAnimator.ofInt(binding.logoView.measuredHeight, (binding.logoView.measuredHeight * 0.75).toInt()) scaleLogoAnimation.addUpdateListener { valueAnimator -> val value = valueAnimator.animatedValue as? Int ?: 0 - val layoutParams = logoView.layoutParams + val layoutParams = binding.logoView.layoutParams layoutParams.height = value - logoView.layoutParams = layoutParams + binding.logoView.layoutParams = layoutParams } if (isRegistering) { newGameAlphaAnimation.startDelay = 600 @@ -509,10 +504,10 @@ class LoginActivity : BaseActivity(), Consumer { showLoginAlphaAnimation.duration = 400 newGameAlphaAnimation.addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - newGameButton.visibility = View.GONE - showLoginButton.visibility = View.GONE - scrollView.visibility = View.VISIBLE - scrollView.alpha = 1f + binding.newGameButton.visibility = View.GONE + binding.showLoginButton.visibility = View.GONE + binding.loginScrollview.visibility = View.VISIBLE + binding.loginScrollview.alpha = 1f } }) } else { @@ -521,21 +516,21 @@ class LoginActivity : BaseActivity(), Consumer { newGameAlphaAnimation.duration = 400 showLoginAlphaAnimation.addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - newGameButton.visibility = View.GONE - showLoginButton.visibility = View.GONE - scrollView.visibility = View.VISIBLE - scrollView.alpha = 1f + binding.newGameButton.visibility = View.GONE + binding.showLoginButton.visibility = View.GONE + binding.loginScrollview.visibility = View.VISIBLE + binding.loginScrollview.alpha = 1f } }) } - val backAlphaAnimation = ObjectAnimator.ofFloat (backButton, View.ALPHA, 1.toFloat()).setDuration(800) + val backAlphaAnimation = ObjectAnimator.ofFloat(binding.backButton, View.ALPHA, 1.toFloat()).setDuration(800) val showAnimation = AnimatorSet() showAnimation.playTogether(panAnimation, newGameAlphaAnimation, showLoginAlphaAnimation, scaleLogoAnimation) showAnimation.play(backAlphaAnimation).after(panAnimation) - for (i in 0 until formWrapper.childCount) { - val view = formWrapper.getChildAt(i) + for (i in 0 until binding.formWrapper.childCount) { + val view = binding.formWrapper.getChildAt(i) view.alpha = 0f - val animator = ObjectAnimator.ofFloat (view, View.ALPHA, 1.toFloat()).setDuration(400) + val animator = ObjectAnimator.ofFloat(view, View.ALPHA, 1.toFloat()).setDuration(400) animator.startDelay = (100 * i).toLong() showAnimation.play(animator).after(panAnimation) } @@ -545,26 +540,26 @@ class LoginActivity : BaseActivity(), Consumer { private fun hideForm() { isShowingForm = false - val panAnimation = ObjectAnimator.ofInt(backgroundContainer, "scrollY", backgroundContainer.bottom).setDuration(1000) - val newGameAlphaAnimation = ObjectAnimator.ofFloat (newGameButton, View.ALPHA, 1.toFloat()).setDuration(700) - val showLoginAlphaAnimation = ObjectAnimator.ofFloat (showLoginButton, View.ALPHA, 1.toFloat()).setDuration(700) - val scaleLogoAnimation = ValueAnimator.ofInt(logoView.measuredHeight, (logoView.measuredHeight * 1.333333).toInt()) + val panAnimation = ObjectAnimator.ofInt(binding.backgroundContainer, "scrollY", binding.backgroundContainer.bottom).setDuration(1000) + val newGameAlphaAnimation = ObjectAnimator.ofFloat(binding.newGameButton, View.ALPHA, 1.toFloat()).setDuration(700) + val showLoginAlphaAnimation = ObjectAnimator.ofFloat(binding.showLoginButton, View.ALPHA, 1.toFloat()).setDuration(700) + val scaleLogoAnimation = ValueAnimator.ofInt(binding.logoView.measuredHeight, (binding.logoView.measuredHeight * 1.333333).toInt()) scaleLogoAnimation.addUpdateListener { valueAnimator -> val value = valueAnimator.animatedValue as? Int - val layoutParams = logoView.layoutParams + val layoutParams = binding.logoView.layoutParams layoutParams.height = value ?: 0 - logoView.layoutParams = layoutParams + binding.logoView.layoutParams = layoutParams } showLoginAlphaAnimation.startDelay = 300 - val scrollViewAlphaAnimation = ObjectAnimator.ofFloat (scrollView, View.ALPHA, 0.toFloat()).setDuration(800) + val scrollViewAlphaAnimation = ObjectAnimator.ofFloat(binding.loginScrollview, View.ALPHA, 0.toFloat()).setDuration(800) scrollViewAlphaAnimation.addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - newGameButton.visibility = View.VISIBLE - showLoginButton.visibility = View.VISIBLE - scrollView.visibility = View.INVISIBLE + binding.newGameButton.visibility = View.VISIBLE + binding.showLoginButton.visibility = View.VISIBLE + binding.loginScrollview.visibility = View.INVISIBLE } }) - val backAlphaAnimation = ObjectAnimator.ofFloat (backButton, View.ALPHA, 0.toFloat()).setDuration(800) + val backAlphaAnimation = ObjectAnimator.ofFloat(binding.backButton, View.ALPHA, 0.toFloat()).setDuration(800) val showAnimation = AnimatorSet() showAnimation.playTogether(panAnimation, scrollViewAlphaAnimation, backAlphaAnimation, scaleLogoAnimation) showAnimation.play(newGameAlphaAnimation).after(scrollViewAlphaAnimation) @@ -588,7 +583,7 @@ class LoginActivity : BaseActivity(), Consumer { alertDialog.setMessage(R.string.forgot_password_description) alertDialog.setAdditionalContentView(input) alertDialog.addButton(R.string.send, true) { _, _ -> - userRepository.sendPasswordResetEmail(input.text.toString()).subscribe(Consumer { showPasswordEmailConfirmation() }, RxErrorHandler.handleEmptyError()) + userRepository.sendPasswordResetEmail(input.text.toString()).subscribe({ showPasswordEmailConfirmation() }, RxErrorHandler.handleEmptyError()) } alertDialog.addCancelButton() alertDialog.show() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt index f6c5bd6f4..9fea7c83f 100755 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt @@ -13,7 +13,6 @@ import android.graphics.Bitmap import android.graphics.Canvas import android.os.Build import android.os.Bundle -import android.os.Handler import android.util.Log import android.view.* import android.widget.FrameLayout @@ -21,8 +20,8 @@ import android.widget.TextView import androidx.appcompat.app.ActionBarDrawerToggle import androidx.core.content.FileProvider import androidx.core.content.edit -import androidx.lifecycle.ViewModelProviders -import androidx.navigation.NavController +import androidx.drawerlayout.widget.DrawerLayout +import androidx.lifecycle.ViewModelProvider import androidx.navigation.NavDestination import androidx.navigation.findNavController import com.facebook.drawee.view.SimpleDraweeView @@ -38,8 +37,7 @@ import com.habitrpg.android.habitica.data.local.UserQuestStatus import com.habitrpg.android.habitica.databinding.ActivityMainBinding import com.habitrpg.android.habitica.events.* import com.habitrpg.android.habitica.events.commands.FeedCommand -import com.habitrpg.android.habitica.extensions.dpToPx -import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler +import com.habitrpg.android.habitica.extensions.* import com.habitrpg.android.habitica.helpers.* import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager import com.habitrpg.android.habitica.interactors.CheckClassSelectionUseCase @@ -76,11 +74,10 @@ import com.habitrpg.android.habitica.widget.DailiesWidgetProvider import com.habitrpg.android.habitica.widget.HabitButtonWidgetProvider import com.habitrpg.android.habitica.widget.TodoListWidgetProvider import io.reactivex.Completable +import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.functions.Action import io.reactivex.functions.Consumer import io.reactivex.schedulers.Schedulers -import io.realm.Realm import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import java.util.* @@ -139,8 +136,6 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { private var resumeFromActivity = false private var userQuestStatus = UserQuestStatus.NO_QUEST - private var connectionIssueHandler: Handler? = null - val userID: String get() = user?.id ?: "" @@ -181,7 +176,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { sideAvatarView = AvatarView(this, showBackground = true, showMount = false, showPet = false) compositeSubscription.add(userRepository.getUser() - .subscribe(Consumer { newUser -> + .subscribe({ newUser -> this@MainActivity.user = newUser this@MainActivity.setUserData() }, RxErrorHandler.handleEmptyError())) @@ -189,11 +184,10 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { userQuestStatus = it })) - val viewModel = ViewModelProviders.of(this) - .get(NotificationsViewModel::class.java) + val viewModel = ViewModelProvider(this).get(NotificationsViewModel::class.java) notificationsViewModel = viewModel - val drawerLayout = findViewById (R.id.drawer_layout) + val drawerLayout = findViewById (R.id.drawer_layout) drawerFragment = supportFragmentManager.findFragmentById(R.id.navigation_drawer) as? NavigationDrawerFragment @@ -201,13 +195,51 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { drawerToggle = object : ActionBarDrawerToggle( this, /* host Activity */ - findViewById(R.id.drawer_layout), /* DrawerLayout object */ + drawerLayout, /* DrawerLayout object */ R.string.navigation_drawer_open, /* "open drawer" description */ R.string.navigation_drawer_close /* "close drawer" description */ ) {} drawerToggle?.drawerArrowDrawable = drawerIcon // Set the drawer toggle as the DrawerListener drawerToggle?.let { drawerLayout.addDrawerListener(it) } + drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener { + private var isOpeningDrawer: Boolean? = null + + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { + val modernHeaderStyle = sharedPreferences.getBoolean("modern_header_style", true) + if (!isUsingNightModeResources() && modernHeaderStyle) { + if (slideOffset < 0.5f && isOpeningDrawer == null) { + window.updateStatusBarColor(getThemeColor(R.attr.colorPrimaryDark), false) + isOpeningDrawer = true + } else if (slideOffset > 0.5f && isOpeningDrawer == null) { + window.updateStatusBarColor(getThemeColor(R.attr.headerBackgroundColor), true) + isOpeningDrawer = false + } + } + } + + override fun onDrawerOpened(drawerView: View) { + val modernHeaderStyle = sharedPreferences.getBoolean("modern_header_style", true) + if (!isUsingNightModeResources() && modernHeaderStyle) { + window.updateStatusBarColor(getThemeColor(R.attr.colorPrimaryDark), false) + } + isOpeningDrawer = null + + drawerFragment?.updatePromo() + } + + override fun onDrawerClosed(drawerView: View) { + val modernHeaderStyle = sharedPreferences.getBoolean("modern_header_style", true) + if (!isUsingNightModeResources() && modernHeaderStyle) { + window.updateStatusBarColor(getThemeColor(R.attr.headerBackgroundColor), true) + } + isOpeningDrawer = null + } + + override fun onDrawerStateChanged(newState: Int) { + + } + }) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setHomeButtonEnabled(true) @@ -239,7 +271,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { "" } if (destination.id == R.id.petDetailRecyclerFragment || destination.id == R.id.mountDetailRecyclerFragment) { - compositeSubscription.add(inventoryRepository.getItem("egg", arguments?.getString("type") ?: "").firstElement().subscribe(Consumer { + compositeSubscription.add(inventoryRepository.getItem("egg", arguments?.getString("type") ?: "").firstElement().subscribe({ binding.toolbarTitle.text = if (destination.id == R.id.petDetailRecyclerFragment) { (it as? Egg)?.text } else { @@ -379,22 +411,22 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { displayDeathDialogIfNeeded() YesterdailyDialog.showDialogIfNeeded(this, user?.id, userRepository, taskRepository) - if (user?.flags?.isVerifiedUsername == false && isActivityVisible) { + if (user?.flags?.verifiedUsername == false && isActivityVisible) { val intent = Intent(this, VerifyUsernameActivity::class.java) startActivity(intent) } val quest = user?.party?.quest if (quest?.completed?.isNotBlank() == true) { - compositeSubscription.add(inventoryRepository.getQuestContent(user?.party?.quest?.completed ?: "").firstElement().subscribe(Consumer { + compositeSubscription.add(inventoryRepository.getQuestContent(user?.party?.quest?.completed ?: "").firstElement().subscribe({ QuestCompletedDialog.showWithQuest(this, it) - userRepository.updateUser(user, "party.quest.completed", "").subscribe(Consumer {}, RxErrorHandler.handleEmptyError()) + userRepository.updateUser(user, "party.quest.completed", "").subscribe({}, RxErrorHandler.handleEmptyError()) }, RxErrorHandler.handleEmptyError())) } if (user?.flags?.welcomed == false) { - compositeSubscription.add(userRepository.updateUser(user, "flags.welcomed", true).subscribe(Consumer {}, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(userRepository.updateUser(user, "flags.welcomed", true).subscribe({}, RxErrorHandler.handleEmptyError())) } if (appConfigManager.enableAdventureGuide()) { @@ -463,7 +495,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { } val pet = event.usingPet compositeSubscription.add(this.inventoryRepository.feedPet(event.usingPet, event.usingFood) - .subscribe(Consumer { feedResponse -> + .subscribe({ feedResponse -> HabiticaSnackbar.showSnackbar(snackbarContainer, feedResponse.message, SnackbarDisplayType.NORMAL) if (feedResponse.value == -1) { val mountWrapper = View.inflate(this, R.layout.pet_imageview, null) as? FrameLayout @@ -539,7 +571,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { faintDialog?.addButton(R.string.faint_button, true) { _, _ -> faintDialog = null user?.let { - userRepository.revive(it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + userRepository.revive(it).subscribe({ }, RxErrorHandler.handleEmptyError()) } } soundManager.loadAndPlayAudio(SoundManager.SoundDeath) @@ -567,8 +599,8 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { pushNotificationManager.addPushDeviceUsingStoredToken() } .flatMap { contentRepository.retrieveContent(this,false) } - .flatMap { contentRepository.retrieveWorldState() } - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError())) + .flatMap { contentRepository.retrieveWorldState(this) } + .subscribe({ }, RxErrorHandler.handleEmptyError())) } } @@ -609,7 +641,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { val updateData = HashMap () updateData[path] = true compositeSubscription.add(userRepository.updateUser(user, updateData) - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError())) + .subscribe({ }, RxErrorHandler.handleEmptyError())) binding.overlayFrameLayout.removeView(this.activeTutorialView) this.removeActiveTutorialView() @@ -621,7 +653,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { } override fun onTutorialDeferred(step: TutorialStep) { - taskRepository.executeTransaction(Realm.Transaction { step.displayedOn = Date() }) + taskRepository.executeTransaction { step.displayedOn = Date() } this.removeActiveTutorialView() } @@ -638,7 +670,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { sharingIntent.type = "*/*" sharingIntent.putExtra(Intent.EXTRA_TEXT, event.sharedMessage) BitmapUtils.clearDirectoryContent("$filesDir/shared_images") - val f = BitmapUtils.saveToShareableFile("$filesDir/shared_images", "${Date().toString()}.png", event.shareImage) + val f = BitmapUtils.saveToShareableFile("$filesDir/shared_images", "${Date()}.png", event.shareImage) val fileUri = f?.let { FileProvider.getUriForFile(this, getString(R.string.content_provider), it) } if (fileUri != null) { sharingIntent.putExtra(Intent.EXTRA_STREAM, fileUri) @@ -724,13 +756,13 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { compositeSubscription.add(Completable.complete() .observeOn(AndroidSchedulers.mainThread()) - .subscribe(Action { + .subscribe({ val alert = HabiticaAlertDialog(this) alert.setAdditionalContentView(view) alert.setTitle(title) alert.addButton(R.string.see_you_tomorrow, true) { _, _ -> apiClient.readNotification(event.notification.id) - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + .subscribe({ }, RxErrorHandler.handleEmptyError()) } alert.show() }, RxErrorHandler.handleEmptyError())) @@ -740,40 +772,40 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { fun showAchievementDialog(event: ShowAchievementDialog) { if (User.ONBOARDING_ACHIEVEMENT_KEYS.contains(event.type) || event.type == Notification.Type.ACHIEVEMENT_ONBOARDING_COMPLETE.type) { if (!appConfigManager.enableAdventureGuide()) { - apiClient.readNotification(event.id) - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + compositeSubscription.add(apiClient.readNotification(event.id) + .subscribe({ }, RxErrorHandler.handleEmptyError())) return } } compositeSubscription.add(Completable.complete() .observeOn(AndroidSchedulers.mainThread()) - .subscribe(Action { + .subscribe({ retrieveUser(true) val dialog = AchievementDialog(this) dialog.isLastOnboardingAchievement = event.isLastOnboardingAchievement dialog.setType(event.type) dialog.enqueue() apiClient.readNotification(event.id) - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + .subscribe({ }, RxErrorHandler.handleEmptyError()) }, RxErrorHandler.handleEmptyError())) } @Subscribe fun showFirstDropDialog(event: ShowFirstDropDialog) { if (!appConfigManager.enableAdventureGuide()) { - apiClient.readNotification(event.id) - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + compositeSubscription.add(apiClient.readNotification(event.id) + .subscribe({ }, RxErrorHandler.handleEmptyError())) return } compositeSubscription.add(Completable.complete() .observeOn(AndroidSchedulers.mainThread()) - .subscribe(Action { + .subscribe({ retrieveUser(true) val dialog = FirstDropDialog(this) dialog.configure(event.egg, event.hatchingPotion) dialog.enqueue() apiClient.readNotification(event.id) - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) + .subscribe({ }, RxErrorHandler.handleEmptyError()) }, RxErrorHandler.handleEmptyError())) } @@ -781,13 +813,13 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { if (event.title != null) { super.onEvent(event) } else { - connectionIssueHandler?.removeCallbacksAndMessages(null) binding.connectionIssueTextview.visibility = View.VISIBLE binding.connectionIssueTextview.text = event.message - connectionIssueHandler = Handler() - connectionIssueHandler?.postDelayed({ - binding.connectionIssueTextview.visibility = View.GONE - }, 5000) + compositeSubscription.add(Observable.just("") + .delay(500, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) + .subscribe( { + binding.connectionIssueTextview.visibility = View.GONE + }, {})) } } @@ -804,7 +836,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { dialog.setAdditionalContentView(petWrapper) dialog.addButton(R.string.equip, true) { _, _ -> inventoryRepository.equip(user, "pet", egg.key + "-" + potion.key) - .subscribe(Consumer {}, RxErrorHandler.handleEmptyError()) + .subscribe({}, RxErrorHandler.handleEmptyError()) } dialog.addButton(R.string.share, false) { hatchingDialog, _ -> val event1 = ShareEvent() @@ -820,12 +852,12 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { } dialog.setExtraCloseButtonVisibility(View.VISIBLE) dialog.enqueue() - }.subscribe(Consumer { }, RxErrorHandler.handleEmptyError())) + }.subscribe({ }, RxErrorHandler.handleEmptyError())) } @Subscribe fun onConsumablePurchased(event: ConsumablePurchasedEvent) { - userRepository.retrieveUser(false, true).subscribe(Consumer {}, RxErrorHandler.handleEmptyError()) + compositeSubscription.add(userRepository.retrieveUser(withTasks = false, forced = true).subscribe({}, RxErrorHandler.handleEmptyError())) } companion object { @@ -835,4 +867,4 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction { const val NOTIFICATION_ACCEPT = 223 const val NOTIFICATION_REJECT = 224 } -} +} \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.kt index 419b7fa23..1b87333f0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MaintenanceActivity.kt @@ -4,61 +4,59 @@ import android.content.Intent import android.os.Bundle import android.text.method.LinkMovementMethod import android.view.View -import android.widget.Button -import android.widget.TextView import androidx.core.net.toUri -import com.facebook.drawee.view.SimpleDraweeView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.api.MaintenanceApiService import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.ApiClient +import com.habitrpg.android.habitica.databinding.ActivityMaintenanceBinding import com.habitrpg.android.habitica.helpers.RxErrorHandler -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.setMarkdown -import com.habitrpg.android.habitica.ui.views.HabiticaEmojiTextView import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.functions.Consumer import io.reactivex.schedulers.Schedulers import javax.inject.Inject class MaintenanceActivity : BaseActivity() { + private lateinit var binding: ActivityMaintenanceBinding + @Inject lateinit var maintenanceService: MaintenanceApiService @Inject lateinit var apiClient: ApiClient - internal val titleTextView: TextView by bindView(R.id.titleTextView) - internal val imageView: SimpleDraweeView by bindView(R.id.imageView) - internal val descriptionTextView: HabiticaEmojiTextView by bindView(R.id.descriptionTextView) - internal val playStoreButton: Button by bindView(R.id.playStoreButton) private var isDeprecationNotice: Boolean = false override fun getLayoutResId(): Int { return R.layout.activity_maintenance } + override fun getContentView(): View { + binding = ActivityMaintenanceBinding.inflate(layoutInflater) + return binding.root + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val data = intent.extras ?: return - this.titleTextView.text = data.getString("title") + binding.titleTextView.text = data.getString("title") @Suppress("DEPRECATION") - imageView.setImageURI(data.getString("imageUrl")?.toUri()) - this.descriptionTextView.setMarkdown(data.getString("description")) - this.descriptionTextView.movementMethod = LinkMovementMethod.getInstance() + binding.imageView.setImageURI(data.getString("imageUrl")?.toUri()) + binding.descriptionTextView.setMarkdown(data.getString("description")) + binding.descriptionTextView.movementMethod = LinkMovementMethod.getInstance() isDeprecationNotice = data.getBoolean("deprecationNotice") if (isDeprecationNotice) { - this.playStoreButton.visibility = View.VISIBLE + binding.playStoreButton.visibility = View.VISIBLE } else { - this.playStoreButton.visibility = View.GONE + binding.playStoreButton.visibility = View.GONE } - playStoreButton.setOnClickListener { openInPlayStore() } + binding.playStoreButton.setOnClickListener { openInPlayStore() } } override fun injectActivity(component: UserComponent?) { @@ -71,7 +69,7 @@ class MaintenanceActivity : BaseActivity() { compositeSubscription.add(this.maintenanceService.maintenanceStatus .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(Consumer { maintenanceResponse -> + .subscribe({ maintenanceResponse -> if (!maintenanceResponse.activeMaintenance) { finish() } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/NotificationsActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/NotificationsActivity.kt index 158cdd770..df584ed99 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/NotificationsActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/NotificationsActivity.kt @@ -8,12 +8,11 @@ import android.view.LayoutInflater import android.view.View import android.widget.* import androidx.core.content.ContextCompat -import androidx.lifecycle.ViewModelProviders +import androidx.lifecycle.ViewModelProvider import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.InventoryRepository import com.habitrpg.android.habitica.data.SocialRepository -import com.habitrpg.android.habitica.databinding.ActivityIntroBinding import com.habitrpg.android.habitica.databinding.ActivityNotificationsBinding import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.Notification @@ -21,7 +20,6 @@ import com.habitrpg.android.habitica.models.inventory.QuestContent import com.habitrpg.android.habitica.models.notifications.* import com.habitrpg.android.habitica.ui.activities.MainActivity.Companion.NOTIFICATION_CLICK import com.habitrpg.android.habitica.ui.viewmodels.NotificationsViewModel -import io.reactivex.functions.Consumer import javax.inject.Inject class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener { @@ -52,10 +50,9 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater - viewModel = ViewModelProviders.of(this) - .get(NotificationsViewModel::class.java) + viewModel = ViewModelProvider(this).get(NotificationsViewModel::class.java) - compositeSubscription.add(viewModel.getNotifications().subscribe(Consumer { + compositeSubscription.add(viewModel.getNotifications().subscribe({ this.setNotifications(it) viewModel.markNotificationsAsSeen(it) }, RxErrorHandler.handleEmptyError())) @@ -78,7 +75,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget override fun onRefresh() { binding.notificationsRefreshLayout.isRefreshing = true - compositeSubscription.add(viewModel.refreshNotifications().subscribe(Consumer { + compositeSubscription.add(viewModel.refreshNotifications().subscribe({ binding.notificationsRefreshLayout.isRefreshing = false }, RxErrorHandler.handleEmptyError())) } @@ -86,10 +83,6 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget private fun setNotifications(notifications: List ) { this.notifications = notifications - if (binding.notificationItems == null) { - return - } - binding.notificationItems.removeAllViewsInLayout() if (notifications.isEmpty()) { @@ -303,7 +296,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget compositeSubscription.add(inventoryRepository.getQuestContent(data?.questKey ?: "") .firstElement() - .subscribe(Consumer { + .subscribe({ updateQuestInvitationView(view, it) }, RxErrorHandler.handleEmptyError())) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ReportMessageActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ReportMessageActivity.kt index 2757bfefc..891700c37 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ReportMessageActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ReportMessageActivity.kt @@ -6,47 +6,29 @@ import android.os.Build import android.os.Build.VERSION_CODES import android.os.Bundle import android.view.View -import android.view.ViewGroup -import android.widget.Button -import android.widget.EditText -import android.widget.ImageButton -import android.widget.TextView import androidx.annotation.RequiresApi -import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.navigation.navArgs -import com.google.android.material.appbar.AppBarLayout import com.google.android.material.bottomsheet.BottomSheetBehavior import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.SocialRepository +import com.habitrpg.android.habitica.databinding.ActivityReportMessageBinding import com.habitrpg.android.habitica.extensions.getThemeColor import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.social.ChatMessage -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard import com.habitrpg.android.habitica.ui.helpers.setMarkdown -import io.reactivex.functions.Consumer import javax.inject.Inject class ReportMessageActivity : BaseActivity() { + private lateinit var binding: ActivityReportMessageBinding + @Inject lateinit var socialRepository: SocialRepository - private val toolbar: Toolbar by bindView(R.id.toolbar) - private val toolbarTextView: TextView by bindView(R.id.toolbar_title) - private val closeButton: ImageButton by bindView(R.id.close_button) - private val reportButton: Button by bindView(R.id.report_button) - private val appBar: AppBarLayout by bindView(R.id.app_bar) - private val bottomSheetView: View by bindView(R.id.bottom_sheet) - private val contentContainer: ViewGroup by bindView(R.id.content_container) - private val dismissTouchView: View by bindView(R.id.touch_outside) - private val titleTextView: TextView by bindView(R.id.title_text_view) - private val messageTextView: TextView by bindView(R.id.message_text_view) - private val additionInfoEditText: EditText by bindView(R.id.additional_info_edittext) - private val reportExplanationTextView: TextView by bindView(R.id.report_explanation_textview) private var raisedElevation = 0f private var messageID: String? = null @@ -60,21 +42,26 @@ class ReportMessageActivity : BaseActivity() { component?.inject(this) } + override fun getContentView(): View { + binding = ActivityReportMessageBinding.inflate(layoutInflater) + return binding.root + } + private var chatMessage: ChatMessage? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) supportActionBar?.title = "" - raisedElevation = appBar.elevation + raisedElevation = binding.appBar.elevation setStatusBarDim(true) - contentContainer.setOnTouchListener { _, _ -> true } - dismissTouchView.setOnClickListener { finish() } - reportExplanationTextView.setMarkdown(getString(R.string.report_explanation)) + binding.contentContainer.setOnTouchListener { _, _ -> true } + binding.touchOutside.setOnClickListener { finish() } + binding.reportExplanationTextview.setMarkdown(getString(R.string.report_explanation)) - BottomSheetBehavior.from (bottomSheetView) - .setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { + BottomSheetBehavior.from (binding.bottomSheet) + .addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { @SuppressLint("SwitchIntDef") override fun onStateChanged(bottomSheet: View, newState: Int) { when (newState) { @@ -91,17 +78,17 @@ class ReportMessageActivity : BaseActivity() { val args = navArgs ().value messageID = args.messageID - titleTextView.text = getString(R.string.report_message_title, args.profileName) - messageTextView.text = args.text + binding.titleTextView.text = getString(R.string.report_message_title, args.profileName) + binding.messageTextView.text = args.text messageID?.let {messageID -> - compositeSubscription.add(socialRepository.getChatmessage(messageID).subscribe(Consumer { + compositeSubscription.add(socialRepository.getChatmessage(messageID).subscribe({ chatMessage = it }, RxErrorHandler.handleEmptyError())) } - reportButton.setOnClickListener { reportMessage() } - closeButton.setOnClickListener { finish() } + binding.reportButton.setOnClickListener { reportMessage() } + binding.closeButton.setOnClickListener { finish() } } override fun onBackPressed() { @@ -115,9 +102,9 @@ class ReportMessageActivity : BaseActivity() { } chatMessage?.let { isReporting = true - socialRepository.flagMessage(it, additionInfoEditText.text.toString()) + socialRepository.flagMessage(it, binding.additionalInfoEdittext.text.toString()) .doOnError { isReporting = false } - .subscribe(Consumer { + .subscribe({ finish() }, RxErrorHandler.handleEmptyError()) } @@ -125,15 +112,15 @@ class ReportMessageActivity : BaseActivity() { private fun setStatusBarDim(dim: Boolean) { if (dim) { - appBar.elevation = 0f + binding.appBar.elevation = 0f window.statusBarColor = getThemeColor(R.attr.colorPrimaryDark) - closeButton.visibility = View.GONE - toolbarTextView.setTypeface(null, Typeface.BOLD) + binding.closeButton.visibility = View.GONE + binding.toolbarTitle.setTypeface(null, Typeface.BOLD) } else { - appBar.elevation = 8f - window.statusBarColor = ContextCompat.getColor(this, R.color.gray_600) - closeButton.visibility = View.VISIBLE - toolbarTextView.setTypeface(null, Typeface.NORMAL) + binding.appBar.elevation = 8f + window.statusBarColor = ContextCompat.getColor(this, R.color.offset_background) + binding.closeButton.visibility = View.VISIBLE + binding.toolbarTitle.setTypeface(null, Typeface.NORMAL) } if (Build.VERSION.SDK_INT >= VERSION_CODES.M) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt index 288c93de2..ac7f404ca 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SetupActivity.kt @@ -8,7 +8,6 @@ import android.os.Bundle import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager -import android.widget.Button import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.ContextCompat import androidx.core.content.edit @@ -24,23 +23,22 @@ import com.habitrpg.android.habitica.data.ApiClient import com.habitrpg.android.habitica.data.InventoryRepository import com.habitrpg.android.habitica.data.TaskRepository import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.databinding.ActivitySetupBinding import com.habitrpg.android.habitica.helpers.AmplitudeManager import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.fragments.setup.AvatarSetupFragment import com.habitrpg.android.habitica.ui.fragments.setup.TaskSetupFragment import com.habitrpg.android.habitica.ui.fragments.setup.WelcomeFragment -import com.habitrpg.android.habitica.ui.helpers.bindView -import com.habitrpg.android.habitica.ui.views.FadingViewPager -import com.viewpagerindicator.IconPageIndicator import com.viewpagerindicator.IconPagerAdapter import io.reactivex.BackpressureStrategy -import io.reactivex.functions.Consumer import java.util.* import javax.inject.Inject class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { + private lateinit var binding: ActivitySetupBinding + @Inject lateinit var apiClient: ApiClient @Inject @@ -52,11 +50,6 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { @Inject lateinit var taskRepository: TaskRepository - private val pager: FadingViewPager by bindView(R.id.viewPager) - private val nextButton: Button by bindView(R.id.nextButton) - private val previousButton: Button by bindView(R.id.previousButton) - private val indicator: IconPageIndicator by bindView(R.id.view_pager_indicator) - internal var welcomeFragment: WelcomeFragment? = null internal var avatarSetupFragment: AvatarSetupFragment? = null internal var taskSetupFragment: TaskSetupFragment? = null @@ -65,16 +58,21 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { private var createdTasks = false private val isLastPage: Boolean - get() = this.pager.adapter == null || this.pager.currentItem == (this.pager.adapter?.count ?: 0) - 1 + get() = binding.viewPager.adapter == null || binding.viewPager.currentItem == (binding.viewPager.adapter?.count ?: 0) - 1 override fun getLayoutResId(): Int { return R.layout.activity_setup } + override fun getContentView(): View { + binding = ActivitySetupBinding.inflate(layoutInflater) + return binding.root + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - compositeSubscription.add(userRepository.getUser().subscribe(Consumer { this.onUserReceived(it) }, RxErrorHandler.handleEmptyError())) - compositeSubscription.add(userRepository.retrieveUser().subscribe(Consumer {}, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(userRepository.getUser().subscribe({ this.onUserReceived(it) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(userRepository.retrieveUser().subscribe({}, RxErrorHandler.handleEmptyError())) val additionalData = HashMap () additionalData["status"] = "displayed" AmplitudeManager.sendEvent("setup", AmplitudeManager.EVENT_CATEGORY_BEHAVIOUR, AmplitudeManager.EVENT_HITTYPE_EVENT, additionalData) @@ -83,7 +81,7 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { for (language in resources.getStringArray(R.array.LanguageValues)) { if (language == currentDeviceLanguage) { compositeSubscription.add(apiClient.registrationLanguage(currentDeviceLanguage) - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError())) + .subscribe({ }, RxErrorHandler.handleEmptyError())) } } @@ -96,10 +94,10 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { window.statusBarColor = ContextCompat.getColor(this, R.color.days_gray) } - pager.disableFading = true + binding.viewPager.disableFading = true - previousButton.setOnClickListener { previousClicked() } - nextButton.setOnClickListener { nextClicked() } + binding.previousButton.setOnClickListener { previousClicked() } + binding.nextButton.setOnClickListener { nextClicked() } } override fun injectActivity(component: UserComponent?) { @@ -114,10 +112,10 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { private fun setupViewpager() { val fragmentManager = supportFragmentManager - pager.adapter = ViewPageAdapter(fragmentManager) + binding.viewPager.adapter = ViewPageAdapter(fragmentManager) - pager.addOnPageChangeListener(this) - indicator.setViewPager(pager) + binding.viewPager.addOnPageChangeListener(this) + binding.viewPagerIndicator.setViewPager(binding.viewPager) } private fun nextClicked() { @@ -137,45 +135,45 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { this.completedSetup = true createdTasks = true newTasks?.let { - this.taskRepository.createTasks(it).subscribe(Consumer { onUserReceived(user) }, RxErrorHandler.handleEmptyError()) + this.taskRepository.createTasks(it).subscribe({ onUserReceived(user) }, RxErrorHandler.handleEmptyError()) } - } else if (pager.currentItem == 0) { + } else if (binding.viewPager.currentItem == 0) { confirmNames(welcomeFragment?.displayName ?: "", welcomeFragment?.username ?: "") val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager imm?.hideSoftInputFromWindow(currentFocus?.windowToken, 0) } - this.pager.currentItem = this.pager.currentItem + 1 + binding.viewPager.currentItem = binding.viewPager.currentItem + 1 } private fun previousClicked() { - this.pager.currentItem = this.pager.currentItem - 1 + binding.viewPager.currentItem = binding.viewPager.currentItem - 1 } private fun setPreviousButtonEnabled(enabled: Boolean) { val leftDrawable: Drawable? if (enabled) { - previousButton.setText(R.string.action_back) + binding.previousButton.setText(R.string.action_back) leftDrawable = AppCompatResources.getDrawable(this, R.drawable.back_arrow_enabled) } else { - previousButton.text = null + binding.previousButton.text = null leftDrawable = AppCompatResources.getDrawable(this, R.drawable.back_arrow_disabled) } - previousButton.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null) + binding.previousButton.setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null) } private fun setNextButtonEnabled(enabled: Boolean) { - nextButton.isEnabled = enabled + binding.nextButton.isEnabled = enabled val rightDrawable = AppCompatResources.getDrawable(this, R.drawable.forward_arrow_enabled) if (enabled) { - nextButton.setTextColor(ContextCompat.getColor(this, R.color.white)) + binding.nextButton.setTextColor(ContextCompat.getColor(this, R.color.white)) rightDrawable?.alpha = 255 } else { - nextButton.setTextColor(ContextCompat.getColor(this, R.color.white_50_alpha)) + binding.nextButton.setTextColor(ContextCompat.getColor(this, R.color.white_50_alpha)) rightDrawable?.alpha = 127 } - nextButton.setCompoundDrawablesWithIntrinsicBounds(null, null, rightDrawable, null) + binding.nextButton.setCompoundDrawablesWithIntrinsicBounds(null, null, rightDrawable, null) } override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) = Unit @@ -184,15 +182,15 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { when { position == 0 -> { this.setPreviousButtonEnabled(false) - this.nextButton.text = this.getString(R.string.next_button) + binding.nextButton.text = this.getString(R.string.next_button) } isLastPage -> { this.setPreviousButtonEnabled(true) - this.nextButton.text = this.getString(R.string.intro_finish_button) + binding.nextButton.text = this.getString(R.string.intro_finish_button) } else -> { this.setPreviousButtonEnabled(true) - this.nextButton.text = this.getString(R.string.next_button) + binding.nextButton.text = this.getString(R.string.next_button) } } } @@ -205,7 +203,7 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { additionalData["status"] = "completed" AmplitudeManager.sendEvent("setup", AmplitudeManager.EVENT_CATEGORY_BEHAVIOUR, AmplitudeManager.EVENT_HITTYPE_EVENT, additionalData) - compositeSubscription.add(userRepository.updateUser(user, "flags.welcomed", true).subscribe(Consumer { + compositeSubscription.add(userRepository.updateUser(user, "flags.welcomed", true).subscribe({ if (!compositeSubscription.isDisposed) { compositeSubscription.dispose() } @@ -214,7 +212,7 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { return } this.user = user - if (pager.adapter == null) { + if (binding.viewPager.adapter == null) { setupViewpager() } avatarSetupFragment?.setUser(user) @@ -231,7 +229,7 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { private fun confirmNames(displayName: String, username: String) { compositeSubscription.add(userRepository.updateUser(null, "profile.name", displayName) .flatMap { userRepository.updateLoginName(username).toFlowable() } - .subscribe(Consumer { }, RxErrorHandler.handleEmptyError())) + .subscribe({ }, RxErrorHandler.handleEmptyError())) } private inner class ViewPageAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm), IconPagerAdapter { @@ -242,7 +240,7 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { val fragment = AvatarSetupFragment() fragment.activity = this@SetupActivity fragment.setUser(user) - fragment.width = pager.width + fragment.width = binding.viewPager.width avatarSetupFragment = fragment fragment } @@ -270,7 +268,7 @@ class SetupActivity : BaseActivity(), ViewPager.OnPageChangeListener { avatarSetupFragment = item item.activity = this@SetupActivity item.setUser(user) - item.width = pager.width + item.width = binding.viewPager.width } is TaskSetupFragment -> { taskSetupFragment = item diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.kt index 09d6ce46f..5375b29c9 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillMemberActivity.kt @@ -3,21 +3,19 @@ package com.habitrpg.android.habitica.ui.activities import android.app.Activity import android.content.Intent import android.os.Bundle +import android.view.View import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.SocialRepository import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.databinding.ActivitySkillMembersBinding import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.ui.adapter.social.PartyMemberRecyclerViewAdapter -import com.habitrpg.android.habitica.ui.helpers.bindView -import io.reactivex.functions.Consumer import javax.inject.Inject class SkillMemberActivity : BaseActivity() { - private val recyclerView: RecyclerView by bindView(R.id.recyclerView) - + private lateinit var binding: ActivitySkillMembersBinding private var viewAdapter: PartyMemberRecyclerViewAdapter? = null @Inject @@ -33,6 +31,11 @@ class SkillMemberActivity : BaseActivity() { component?.inject(this) } + override fun getContentView(): View { + binding = ActivitySkillMembersBinding.inflate(layoutInflater) + return binding.root + } + public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setupToolbar(findViewById(R.id.toolbar)) @@ -40,19 +43,19 @@ class SkillMemberActivity : BaseActivity() { } private fun loadMemberList() { - recyclerView.layoutManager = LinearLayoutManager(this) + binding.recyclerView.layoutManager = LinearLayoutManager(this) viewAdapter = PartyMemberRecyclerViewAdapter(null, true) - viewAdapter?.getUserClickedEvents()?.subscribe(Consumer { userId -> + viewAdapter?.getUserClickedEvents()?.subscribe({ userId -> val resultIntent = Intent() resultIntent.putExtra("member_id", userId) setResult(Activity.RESULT_OK, resultIntent) finish() }, RxErrorHandler.handleEmptyError())?.let { compositeSubscription.add(it) } - recyclerView.adapter = viewAdapter + binding.recyclerView.adapter = viewAdapter compositeSubscription.add(userRepository.getUser() .firstElement() .flatMap { user -> socialRepository.getGroupMembers(user.party?.id ?: "").firstElement() } - .subscribe(Consumer { viewAdapter?.updateData(it) }, RxErrorHandler.handleEmptyError())) + .subscribe({ viewAdapter?.updateData(it) }, RxErrorHandler.handleEmptyError())) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.kt index 50b1f405c..dbdbbffcc 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/SkillTasksActivity.kt @@ -5,33 +5,30 @@ import android.content.Intent import android.os.Bundle import android.util.SparseArray import android.view.MenuItem +import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentPagerAdapter -import androidx.viewpager.widget.ViewPager -import com.google.android.material.tabs.TabLayout import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.TaskRepository +import com.habitrpg.android.habitica.databinding.ActivitySkillTasksBinding import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.modules.AppModule import com.habitrpg.android.habitica.ui.fragments.skills.SkillTasksRecyclerViewFragment -import com.habitrpg.android.habitica.ui.helpers.bindView -import io.reactivex.functions.Consumer import javax.inject.Inject import javax.inject.Named class SkillTasksActivity : BaseActivity() { + private lateinit var binding: ActivitySkillTasksBinding + @Inject lateinit var taskRepository: TaskRepository @field:[Inject Named(AppModule.NAMED_USER_ID)] lateinit var userId: String - private val viewPager: ViewPager by bindView(R.id.viewPager) - private val tabLayout: TabLayout by bindView(R.id.tab_layout) - internal var viewFragmentsDictionary = SparseArray () override fun getLayoutResId(): Int { @@ -44,6 +41,11 @@ class SkillTasksActivity : BaseActivity() { loadTaskLists() } + override fun getContentView(): View { + binding = ActivitySkillTasksBinding.inflate(layoutInflater) + return binding.root + } + override fun injectActivity(component: UserComponent?) { component?.inject(this) } @@ -51,7 +53,7 @@ class SkillTasksActivity : BaseActivity() { private fun loadTaskLists() { val fragmentManager = supportFragmentManager - viewPager.adapter = object : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + binding.viewPager.adapter = object : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { override fun getItem(position: Int): Fragment { val fragment = SkillTasksRecyclerViewFragment() @@ -61,7 +63,7 @@ class SkillTasksActivity : BaseActivity() { else -> Task.TYPE_TODO } - compositeSubscription.add(fragment.getTaskSelectionEvents().subscribe(Consumer { task -> taskSelected(task) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(fragment.getTaskSelectionEvents().subscribe({ task -> taskSelected(task) }, RxErrorHandler.handleEmptyError())) viewFragmentsDictionary.put(position, fragment) @@ -77,7 +79,7 @@ class SkillTasksActivity : BaseActivity() { else -> Task.TYPE_TODO } - compositeSubscription.add(item.getTaskSelectionEvents().subscribe(Consumer { task -> taskSelected(task) }, RxErrorHandler.handleEmptyError())) + compositeSubscription.add(item.getTaskSelectionEvents().subscribe({ task -> taskSelected(task) }, RxErrorHandler.handleEmptyError())) viewFragmentsDictionary.put(position, item) } return item @@ -98,7 +100,7 @@ class SkillTasksActivity : BaseActivity() { } - tabLayout.setupWithViewPager(viewPager) + binding.tabLayout.setupWithViewPager(binding.viewPager) } fun taskSelected(task: Task) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt index f4bcb4ac9..05444f097 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt @@ -1,29 +1,28 @@ package com.habitrpg.android.habitica.ui.activities import android.app.Activity -import android.content.Context import android.content.Intent +import android.content.SharedPreferences import android.content.res.ColorStateList import android.graphics.Typeface import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.os.Handler import android.view.* -import android.view.inputmethod.InputMethodManager import android.widget.CheckBox -import android.widget.EditText -import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.widget.AppCompatCheckBox -import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.core.view.children import androidx.core.view.forEachIndexed import androidx.core.widget.NestedScrollView -import com.google.android.material.textfield.TextInputLayout import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent -import com.habitrpg.android.habitica.data.* +import com.habitrpg.android.habitica.data.ChallengeRepository +import com.habitrpg.android.habitica.data.TagRepository +import com.habitrpg.android.habitica.data.TaskRepository +import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.databinding.ActivityTaskFormBinding import com.habitrpg.android.habitica.extensions.OnChangeTextWatcher import com.habitrpg.android.habitica.extensions.addCancelButton import com.habitrpg.android.habitica.extensions.dpToPx @@ -35,11 +34,8 @@ import com.habitrpg.android.habitica.models.social.Challenge import com.habitrpg.android.habitica.models.tasks.HabitResetOption import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.models.user.Stats -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.helpers.dismissKeyboard import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog -import com.habitrpg.android.habitica.ui.views.tasks.form.* -import io.reactivex.functions.Consumer import io.realm.RealmList import java.util.* import javax.inject.Inject @@ -47,6 +43,7 @@ import javax.inject.Inject class TaskFormActivity : BaseActivity() { + private lateinit var binding: ActivityTaskFormBinding private var userScrolled: Boolean = false private var isSaving: Boolean = false @Inject @@ -60,44 +57,6 @@ class TaskFormActivity : BaseActivity() { @Inject lateinit var challengeRepository: ChallengeRepository - private val toolbar: Toolbar by bindView(R.id.toolbar) - private val scrollView: NestedScrollView by bindView(R.id.scroll_view) - private val upperTextWrapper: LinearLayout by bindView(R.id.upper_text_wrapper) - private val textInputLayout: TextInputLayout by bindView(R.id.text_input_layout) - private val textEditText: EditText by bindView(R.id.text_edit_text) - private val notesInputLayout: TextInputLayout by bindView(R.id.notes_input_layout) - private val notesEditText: EditText by bindView(R.id.notes_edit_text) - private val habitScoringButtons: HabitScoringButtonsView by bindView(R.id.habit_scoring_buttons) - private val checklistTitleView: TextView by bindView(R.id.checklist_title) - private val checklistContainer: ChecklistContainer by bindView(R.id.checklist_container) - private val habitResetStreakTitleView: TextView by bindView(R.id.habit_reset_streak_title) - private val habitResetStreakButtons: HabitResetStreakButtons by bindView(R.id.habit_reset_streak_buttons) - private val taskSchedulingTitleView: TextView by bindView(R.id.scheduling_title) - private val taskSchedulingControls: TaskSchedulingControls by bindView(R.id.scheduling_controls) - private val adjustStreakWrapper: ViewGroup by bindView(R.id.adjust_streak_wrapper) - private val adjustStreakTitleView: TextView by bindView(R.id.adjust_streak_title) - private val habitAdjustPositiveStreakView: EditText by bindView(R.id.habit_adjust_positive_streak) - private val habitAdjustNegativeStreakView: EditText by bindView(R.id.habit_adjust_negative_streak) - private val remindersTitleView: TextView by bindView(R.id.reminders_title) - private val remindersContainer: ReminderContainer by bindView(R.id.reminders_container) - - private val taskDifficultyTitleView: TextView by bindView(R.id.task_difficulty_title) - private val taskDifficultyButtons: TaskDifficultyButtons by bindView(R.id.task_difficulty_buttons) - - private val statWrapper: ViewGroup by bindView(R.id.stat_wrapper) - private val statStrengthButton: TextView by bindView(R.id.stat_strength_button) - private val statIntelligenceButton: TextView by bindView(R.id.stat_intelligence_button) - private val statConstitutionButton: TextView by bindView(R.id.stat_constitution_button) - private val statPerceptionButton: TextView by bindView(R.id.stat_perception_button) - - private val rewardValueTitleView: TextView by bindView(R.id.reward_value_title) - private val stepperValueFormView: StepperValueFormView by bindView(R.id.reward_value) - - private val tagsTitleView: TextView by bindView(R.id.tags_title) - private val tagsWrapper: LinearLayout by bindView(R.id.tags_wrapper) - - private val challengeNameView: TextView by bindView(R.id.challenge_name_view) - private var challenge: Challenge? = null private var isCreating = true @@ -119,10 +78,10 @@ class TaskFormActivity : BaseActivity() { private var tintColor: Int = 0 set(value) { field = value - taskDifficultyButtons.tintColor = value - habitScoringButtons.tintColor = value - habitResetStreakButtons.tintColor = value - taskSchedulingControls.tintColor = value + binding.taskDifficultyButtons.tintColor = value + binding.habitScoringButtons.tintColor = value + binding.habitResetStreakButtons.tintColor = value + binding.taskSchedulingControls.tintColor = value updateTagViewsColors() } @@ -130,11 +89,17 @@ class TaskFormActivity : BaseActivity() { return R.layout.activity_task_form } + override fun getContentView(): View { + binding = ActivityTaskFormBinding.inflate(layoutInflater) + return binding.root + } + override fun injectActivity(component: UserComponent?) { component?.inject(this) } override fun onCreate(savedInstanceState: Bundle?) { + overrideModernHeader = false val bundle = intent.extras ?: return val taskId = bundle.getString(TASK_ID_KEY) @@ -155,18 +120,20 @@ class TaskFormActivity : BaseActivity() { super.onCreate(savedInstanceState) if (forcedTheme == "yellow") { - taskDifficultyButtons.textTintColor = ContextCompat.getColor(this, R.color.yellow_5) - habitScoringButtons.textTintColor = ContextCompat.getColor(this, R.color.yellow_5) + binding.taskDifficultyButtons.textTintColor = ContextCompat.getColor(this, R.color.text_yellow) + binding.habitScoringButtons.textTintColor = ContextCompat.getColor(this, R.color.text_yellow) + } else if (forcedTheme == "purple") { + binding.taskDifficultyButtons.textTintColor = ContextCompat.getColor(this, R.color.text_brand_neon) + binding.habitScoringButtons.textTintColor = ContextCompat.getColor(this, R.color.text_brand_neon) } - - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true) tintColor = getThemeColor(R.attr.taskFormTint) val upperTintColor = if (forcedTheme == "purple") getThemeColor(R.attr.taskFormTint) else getThemeColor(R.attr.colorAccent) supportActionBar?.setBackgroundDrawable(ColorDrawable(upperTintColor)) - upperTextWrapper.setBackgroundColor(upperTintColor) + binding.upperTextWrapper.setBackgroundColor(upperTintColor) isChallengeTask = bundle.getBoolean(IS_CHALLENGE_TASK, false) @@ -176,35 +143,35 @@ class TaskFormActivity : BaseActivity() { compositeSubscription.add(tagRepository.getTags() .map { tagRepository.getUnmanagedCopy(it) } - .subscribe(Consumer { + .subscribe({ tags = it setTagViews() }, RxErrorHandler.handleEmptyError())) - compositeSubscription.add(userRepository.getUser().subscribe(Consumer { + compositeSubscription.add(userRepository.getUser().subscribe({ usesTaskAttributeStats = it.preferences?.allocationMode == "taskbased" && it.preferences?.automaticAllocation == true configureForm() }, RxErrorHandler.handleEmptyError())) - textEditText.addTextChangedListener(OnChangeTextWatcher { _, _, _, _ -> + binding.textEditText.addTextChangedListener(OnChangeTextWatcher { _, _, _, _ -> checkCanSave() }) - textEditText.onFocusChangeListener = View.OnFocusChangeListener { _, isFocused -> - textInputLayout.alpha = if (isFocused) 1.0f else 0.75f + binding.textEditText.onFocusChangeListener = View.OnFocusChangeListener { _, isFocused -> + binding.textInputLayout.alpha = if (isFocused) 0.8f else 0.6f window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) } - notesEditText.onFocusChangeListener = View.OnFocusChangeListener { _, isFocused -> - notesInputLayout.alpha = if (isFocused) 1.0f else 0.75f + binding.notesEditText.onFocusChangeListener = View.OnFocusChangeListener { _, isFocused -> + binding.notesInputLayout.alpha = if (isFocused) 0.8f else 0.6f } - statStrengthButton.setOnClickListener { selectedStat = Stats.STRENGTH } - statIntelligenceButton.setOnClickListener { selectedStat = Stats.INTELLIGENCE } - statConstitutionButton.setOnClickListener { selectedStat = Stats.CONSTITUTION } - statPerceptionButton.setOnClickListener { selectedStat = Stats.PERCEPTION } - scrollView.setOnTouchListener { view, event -> - userScrolled = view == scrollView && (event.action == MotionEvent.ACTION_SCROLL || event.action == MotionEvent.ACTION_MOVE) + binding.statStrengthButton.setOnClickListener { selectedStat = Stats.STRENGTH } + binding.statIntelligenceButton.setOnClickListener { selectedStat = Stats.INTELLIGENCE } + binding.statConstitutionButton.setOnClickListener { selectedStat = Stats.CONSTITUTION } + binding.statPerceptionButton.setOnClickListener { selectedStat = Stats.PERCEPTION } + binding.scrollView.setOnTouchListener { view, event -> + userScrolled = view == binding.scrollView && (event.action == MotionEvent.ACTION_SCROLL || event.action == MotionEvent.ACTION_MOVE) return@setOnTouchListener false } - scrollView.setOnScrollChangeListener { _: NestedScrollView?, _: Int, _: Int, _: Int, _: Int -> + binding.scrollView.setOnScrollChangeListener { _: NestedScrollView?, _: Int, _: Int, _: Int, _: Int -> if (userScrolled) { dismissKeyboard() } @@ -214,16 +181,16 @@ class TaskFormActivity : BaseActivity() { when { taskId != null -> { isCreating = false - compositeSubscription.add(taskRepository.getUnmanagedTask(taskId).firstElement().subscribe(Consumer { + compositeSubscription.add(taskRepository.getUnmanagedTask(taskId).firstElement().subscribe({ task = it //tintColor = ContextCompat.getColor(this, it.mediumTaskColor) fillForm(it) task?.challengeID?.let { challengeID -> compositeSubscription.add(challengeRepository.retrieveChallenge(challengeID) - .subscribe(Consumer { challenge -> + .subscribe({ challenge -> this.challenge = challenge - challengeNameView.text = getString(R.string.challenge_task_name, challenge.name) - challengeNameView.visibility = View.VISIBLE + binding.challengeNameView.text = getString(R.string.challenge_task_name, challenge.name) + binding.challengeNameView.visibility = View.VISIBLE }, RxErrorHandler.handleEmptyError())) } }, RxErrorHandler.handleEmptyError())) @@ -243,9 +210,15 @@ class TaskFormActivity : BaseActivity() { configureForm() } + override fun loadTheme(sharedPreferences: SharedPreferences, forced: Boolean) { + super.loadTheme(sharedPreferences, forced) + val upperTintColor = if (forcedTheme == "purple") getThemeColor(R.attr.taskFormTint) else getThemeColor(R.attr.colorAccent) + window.statusBarColor = upperTintColor + } + override fun onStart() { super.onStart() - textEditText.requestFocus() + binding.textEditText.requestFocus() } override fun onCreateOptionsMenu(menu: Menu): Boolean { @@ -271,7 +244,7 @@ class TaskFormActivity : BaseActivity() { } private fun checkCanSave() { - val newCanSave = textEditText.text.isNotBlank() + val newCanSave = binding.textEditText.text?.isNotBlank() == true if (newCanSave != canSave) { invalidateOptionsMenu() } @@ -280,53 +253,53 @@ class TaskFormActivity : BaseActivity() { private fun configureForm() { val habitViewsVisibility = if (taskType == Task.TYPE_HABIT) View.VISIBLE else View.GONE - habitScoringButtons.visibility = habitViewsVisibility - habitResetStreakTitleView.visibility = habitViewsVisibility - habitResetStreakButtons.visibility = habitViewsVisibility - habitAdjustNegativeStreakView.visibility = habitViewsVisibility + binding.habitScoringButtons.visibility = habitViewsVisibility + binding.habitResetStreakTitleView.visibility = habitViewsVisibility + binding.habitResetStreakButtons.visibility = habitViewsVisibility + binding.habitAdjustNegativeStreakView.visibility = habitViewsVisibility val habitDailyVisibility = if (taskType == Task.TYPE_DAILY || taskType == Task.TYPE_HABIT) View.VISIBLE else View.GONE - adjustStreakTitleView.visibility = habitDailyVisibility - adjustStreakWrapper.visibility = habitDailyVisibility + binding.adjustStreakTitleView.visibility = habitDailyVisibility + binding.adjustStreakWrapper.visibility = habitDailyVisibility if (taskType == Task.TYPE_HABIT) { - habitAdjustPositiveStreakView.hint = getString(R.string.positive_habit_form) + binding.habitAdjustPositiveStreakView.hint = getString(R.string.positive_habit_form) } else { - habitAdjustPositiveStreakView.hint = getString(R.string.streak) + binding.habitAdjustPositiveStreakView.hint = getString(R.string.streak) } val todoDailyViewsVisibility = if (taskType == Task.TYPE_DAILY || taskType == Task.TYPE_TODO) View.VISIBLE else View.GONE - checklistTitleView.visibility = if (isChallengeTask) View.GONE else todoDailyViewsVisibility - checklistContainer.visibility = if (isChallengeTask) View.GONE else todoDailyViewsVisibility + binding.checklistTitleView.visibility = if (isChallengeTask) View.GONE else todoDailyViewsVisibility + binding.checklistContainer.visibility = if (isChallengeTask) View.GONE else todoDailyViewsVisibility - remindersTitleView.visibility = if (isChallengeTask) View.GONE else todoDailyViewsVisibility - remindersContainer.visibility = if (isChallengeTask) View.GONE else todoDailyViewsVisibility - remindersContainer.taskType = taskType + binding.remindersTitleView.visibility = if (isChallengeTask) View.GONE else todoDailyViewsVisibility + binding.remindersContainer.visibility = if (isChallengeTask) View.GONE else todoDailyViewsVisibility + binding.remindersContainer.taskType = taskType - taskSchedulingTitleView.visibility = todoDailyViewsVisibility - taskSchedulingControls.visibility = todoDailyViewsVisibility - taskSchedulingControls.taskType = taskType + binding.schedulingTitleView.visibility = todoDailyViewsVisibility + binding.taskSchedulingControls.visibility = todoDailyViewsVisibility + binding.taskSchedulingControls.taskType = taskType val rewardHideViews = if (taskType == Task.TYPE_REWARD) View.GONE else View.VISIBLE - taskDifficultyTitleView.visibility = rewardHideViews - taskDifficultyButtons.visibility = rewardHideViews + binding.taskDifficultyTitleView.visibility = rewardHideViews + binding.taskDifficultyButtons.visibility = rewardHideViews val rewardViewsVisibility = if (taskType == Task.TYPE_REWARD) View.VISIBLE else View.GONE - rewardValueTitleView.visibility = rewardViewsVisibility - stepperValueFormView.visibility = rewardViewsVisibility + binding.rewardValueTitleView.visibility = rewardViewsVisibility + binding.rewardValue.visibility = rewardViewsVisibility - tagsTitleView.visibility = if (isChallengeTask) View.GONE else View.VISIBLE - tagsWrapper.visibility = if (isChallengeTask) View.GONE else View.VISIBLE + binding.tagsTitleView.visibility = if (isChallengeTask) View.GONE else View.VISIBLE + binding.tagsWrapper.visibility = if (isChallengeTask) View.GONE else View.VISIBLE - statWrapper.visibility = if (usesTaskAttributeStats) View.VISIBLE else View.GONE + binding.statWrapper.visibility = if (usesTaskAttributeStats) View.VISIBLE else View.GONE if (isCreating) { - adjustStreakTitleView.visibility = View.GONE - adjustStreakWrapper.visibility = View.GONE + binding.adjustStreakTitleView.visibility = View.GONE + binding.adjustStreakWrapper.visibility = View.GONE } } private fun setTagViews() { - tagsWrapper.removeAllViews() + binding.tagsWrapper.removeAllViews() val padding = 20.dpToPx(this) for (tag in tags) { val view = CheckBox(this) @@ -335,7 +308,7 @@ class TaskFormActivity : BaseActivity() { if (preselectedTags?.contains(tag.id) == true) { view.isChecked = true } - tagsWrapper.addView(view) + binding.tagsWrapper.addView(view) } setAllTagSelections() updateTagViewsColors() @@ -344,7 +317,7 @@ class TaskFormActivity : BaseActivity() { private fun setAllTagSelections() { if (hasPreselectedTags) { tags.forEachIndexed { index, tag -> - val view = tagsWrapper.getChildAt(index) as? CheckBox + val view = binding.tagsWrapper.getChildAt(index) as? CheckBox view?.isChecked = task?.tags?.find { it.id == tag.id } != null } } else { @@ -357,43 +330,43 @@ class TaskFormActivity : BaseActivity() { return } canSave = true - textEditText.setText(task.text) - notesEditText.setText(task.notes) - taskDifficultyButtons.selectedDifficulty = task.priority + binding.textEditText.setText(task.text) + binding.notesEditText.setText(task.notes) + binding.taskDifficultyButtons.selectedDifficulty = task.priority when (taskType) { Task.TYPE_HABIT -> { - habitScoringButtons.isPositive = task.up ?: false - habitScoringButtons.isNegative = task.down ?: false + binding.habitScoringButtons.isPositive = task.up ?: false + binding.habitScoringButtons.isNegative = task.down ?: false task.frequency?.let { if (it.isNotBlank()) { - habitResetStreakButtons.selectedResetOption = HabitResetOption.valueOf(it.toUpperCase(Locale.US)) + binding.habitResetStreakButtons.selectedResetOption = HabitResetOption.valueOf(it.toUpperCase(Locale.US)) } } - habitAdjustPositiveStreakView.setText((task.counterUp ?: 0).toString()) - habitAdjustNegativeStreakView.setText((task.counterDown ?: 0).toString()) - habitAdjustPositiveStreakView.visibility = if (task.up == true) View.VISIBLE else View.GONE - habitAdjustNegativeStreakView.visibility = if (task.down == true) View.VISIBLE else View.GONE + binding.habitAdjustPositiveStreakView.setText((task.counterUp ?: 0).toString()) + binding.habitAdjustNegativeStreakView.setText((task.counterDown ?: 0).toString()) + binding.habitAdjustPositiveStreakView.visibility = if (task.up == true) View.VISIBLE else View.GONE + binding.habitAdjustNegativeStreakView.visibility = if (task.down == true) View.VISIBLE else View.GONE if (task.up != true && task.down != true) { - adjustStreakTitleView.visibility = View.GONE - adjustStreakWrapper.visibility = View.GONE + binding.adjustStreakTitleView.visibility = View.GONE + binding.adjustStreakWrapper.visibility = View.GONE } } Task.TYPE_DAILY -> { - taskSchedulingControls.startDate = task.startDate ?: Date() - taskSchedulingControls.everyX = task.everyX ?: 1 - task.repeat?.let { taskSchedulingControls.weeklyRepeat = it } - taskSchedulingControls.daysOfMonth = task.getDaysOfMonth() - taskSchedulingControls.weeksOfMonth = task.getWeeksOfMonth() - habitAdjustPositiveStreakView.setText((task.streak ?: 0).toString()) - taskSchedulingControls.frequency = task.frequency ?: Task.FREQUENCY_DAILY + binding.taskSchedulingControls.startDate = task.startDate ?: Date() + binding.taskSchedulingControls.everyX = task.everyX ?: 1 + task.repeat?.let { binding.taskSchedulingControls.weeklyRepeat = it } + binding.taskSchedulingControls.daysOfMonth = task.getDaysOfMonth() + binding.taskSchedulingControls.weeksOfMonth = task.getWeeksOfMonth() + binding.habitAdjustPositiveStreakView.setText((task.streak ?: 0).toString()) + binding.taskSchedulingControls.frequency = task.frequency ?: Task.FREQUENCY_DAILY } - Task.TYPE_TODO -> taskSchedulingControls.dueDate = task.dueDate - Task.TYPE_REWARD -> stepperValueFormView.value = task.value + Task.TYPE_TODO -> binding.taskSchedulingControls.dueDate = task.dueDate + Task.TYPE_REWARD -> binding.rewardValue.value = task.value } if (taskType == Task.TYPE_DAILY || taskType == Task.TYPE_TODO) { - task.checklist?.let { checklistContainer.checklistItems = it } - remindersContainer.taskType = taskType - task.reminders?.let { remindersContainer.reminders = it } + task.checklist?.let { binding.checklistContainer.checklistItems = it } + binding.remindersContainer.taskType = taskType + task.reminders?.let { binding.remindersContainer.reminders = it } } task.attribute?.let { selectedStat = it } setAllTagSelections() @@ -401,15 +374,15 @@ class TaskFormActivity : BaseActivity() { private fun setSelectedAttribute(attributeName: String) { if (!usesTaskAttributeStats) return - configureStatsButton(statStrengthButton, attributeName == Stats.STRENGTH ) - configureStatsButton(statIntelligenceButton, attributeName == Stats.INTELLIGENCE ) - configureStatsButton(statConstitutionButton, attributeName == Stats.CONSTITUTION ) - configureStatsButton(statPerceptionButton, attributeName == Stats.PERCEPTION ) + configureStatsButton(binding.statStrengthButton, attributeName == Stats.STRENGTH ) + configureStatsButton(binding.statIntelligenceButton, attributeName == Stats.INTELLIGENCE ) + configureStatsButton(binding.statConstitutionButton, attributeName == Stats.CONSTITUTION ) + configureStatsButton(binding.statPerceptionButton, attributeName == Stats.PERCEPTION ) } private fun configureStatsButton(button: TextView, isSelected: Boolean) { button.background.setTint(if (isSelected) tintColor else ContextCompat.getColor(this, R.color.taskform_gray)) - val textColorID = if (isSelected) R.color.white else R.color.gray_100 + val textColorID = if (isSelected) R.color.window_background else R.color.text_secondary button.setTextColor(ContextCompat.getColor(this, textColorID)) if (isSelected) { button.typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL) @@ -419,13 +392,13 @@ class TaskFormActivity : BaseActivity() { } private fun updateTagViewsColors() { - tagsWrapper.children.forEach { view -> + binding.tagsWrapper.children.forEach { view -> val tagView = view as? AppCompatCheckBox val colorStateList = ColorStateList( arrayOf(intArrayOf(-android.R.attr.state_checked), // unchecked intArrayOf(android.R.attr.state_checked) // checked ), - intArrayOf(ContextCompat.getColor(this, R.color.gray_400), tintColor) + intArrayOf(ContextCompat.getColor(this, R.color.text_dimmed), tintColor) ) tagView?.buttonTintList = colorStateList } @@ -444,41 +417,41 @@ class TaskFormActivity : BaseActivity() { } else { if (!thisTask.isValid) return } - thisTask.text = textEditText.text.toString() - thisTask.notes = notesEditText.text.toString() - thisTask.priority = taskDifficultyButtons.selectedDifficulty + thisTask.text = binding.textEditText.text.toString() + thisTask.notes = binding.notesEditText.text.toString() + thisTask.priority = binding.taskDifficultyButtons.selectedDifficulty if (usesTaskAttributeStats) { thisTask.attribute = selectedStat } if (taskType == Task.TYPE_HABIT) { - thisTask.up = habitScoringButtons.isPositive - thisTask.down = habitScoringButtons.isNegative - thisTask.frequency = habitResetStreakButtons.selectedResetOption.value - if (habitAdjustPositiveStreakView.text.isNotEmpty()) thisTask.counterUp = habitAdjustPositiveStreakView.text.toString().toIntCatchOverflow() - if (habitAdjustNegativeStreakView.text.isNotEmpty()) thisTask.counterDown = habitAdjustNegativeStreakView.text.toString().toIntCatchOverflow() + thisTask.up = binding.habitScoringButtons.isPositive + thisTask.down = binding.habitScoringButtons.isNegative + thisTask.frequency = binding.habitResetStreakButtons.selectedResetOption.value + if (binding.habitAdjustPositiveStreakView.text?.isNotEmpty() == true) thisTask.counterUp = binding.habitAdjustPositiveStreakView.text.toString().toIntCatchOverflow() + if (binding.habitAdjustNegativeStreakView.text?.isNotEmpty() == true) thisTask.counterDown = binding.habitAdjustNegativeStreakView.text.toString().toIntCatchOverflow() } else if (taskType == Task.TYPE_DAILY) { - thisTask.startDate = taskSchedulingControls.startDate - thisTask.everyX = taskSchedulingControls.everyX - thisTask.frequency = taskSchedulingControls.frequency - thisTask.repeat = taskSchedulingControls.weeklyRepeat - thisTask.setDaysOfMonth(taskSchedulingControls.daysOfMonth) - thisTask.setWeeksOfMonth(taskSchedulingControls.weeksOfMonth) - if (habitAdjustPositiveStreakView.text.isNotEmpty()) thisTask.streak = habitAdjustPositiveStreakView.text.toString().toIntCatchOverflow() + thisTask.startDate = binding.taskSchedulingControls.startDate + thisTask.everyX = binding.taskSchedulingControls.everyX + thisTask.frequency = binding.taskSchedulingControls.frequency + thisTask.repeat = binding.taskSchedulingControls.weeklyRepeat + thisTask.setDaysOfMonth(binding.taskSchedulingControls.daysOfMonth) + thisTask.setWeeksOfMonth(binding.taskSchedulingControls.weeksOfMonth) + if (binding.habitAdjustPositiveStreakView.text?.isNotEmpty() == true) thisTask.streak = binding.habitAdjustPositiveStreakView.text.toString().toIntCatchOverflow() } else if (taskType == Task.TYPE_TODO) { - thisTask.dueDate = taskSchedulingControls.dueDate + thisTask.dueDate = binding.taskSchedulingControls.dueDate } else if (taskType == Task.TYPE_REWARD) { - thisTask.value = stepperValueFormView.value + thisTask.value = binding.rewardValue.value } val resultIntent = Intent() resultIntent.putExtra(TASK_TYPE_KEY, taskType) if (!isChallengeTask) { if (taskType == Task.TYPE_DAILY || taskType == Task.TYPE_TODO) { - thisTask.checklist = checklistContainer.checklistItems - thisTask.reminders = remindersContainer.reminders + thisTask.checklist = binding.checklistContainer.checklistItems + thisTask.reminders = binding.remindersContainer.reminders } thisTask.tags = RealmList() - tagsWrapper.forEachIndexed { index, view -> + binding.tagsWrapper.forEachIndexed { index, view -> val tagView = view as? CheckBox if (tagView?.isChecked == true) { thisTask.tags?.add(tags[index]) @@ -506,7 +479,7 @@ class TaskFormActivity : BaseActivity() { } private fun deleteTask() { - if (task?.challengeID?.isNotBlank() == true && task?.challengeBroken?.isNotBlank() != true) { + if (task?.challengeID?.isNotBlank() == true) { showChallengeDeleteTask() return } @@ -514,7 +487,7 @@ class TaskFormActivity : BaseActivity() { alert.setTitle(R.string.are_you_sure) alert.addButton(R.string.delete_task, true) { _, _ -> if (task?.isValid != true) return@addButton - task?.id?.let { taskRepository.deleteTask(it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) } + task?.id?.let { taskRepository.deleteTask(it).subscribe({ }, RxErrorHandler.handleEmptyError()) } finish() } alert.addCancelButton() @@ -522,26 +495,26 @@ class TaskFormActivity : BaseActivity() { } private fun showChallengeDeleteTask() { - compositeSubscription.add(taskRepository.getTasksForChallenge(task?.challengeID).firstElement().subscribe(Consumer { tasks -> + compositeSubscription.add(taskRepository.getTasksForChallenge(task?.challengeID).firstElement().subscribe({ tasks -> val taskCount = tasks.size val alert = HabiticaAlertDialog(this) alert.setTitle(getString(R.string.delete_challenge_task_title)) alert.setMessage(getString(R.string.delete_challenge_task_description, taskCount, challenge?.name ?: "")) - alert.addButton(R.string.leave_delete_task, true, true) { _, _ -> + alert.addButton(R.string.leave_delete_task, isPrimary = true, isDestructive = true) { _, _ -> challenge?.let { compositeSubscription.add(challengeRepository.leaveChallenge(it, "keep-all") .flatMap { taskRepository.deleteTask(task?.id ?: "") } .flatMap { userRepository.retrieveUser(true) } - .subscribe(Consumer { + .subscribe({ finish() }, RxErrorHandler.handleEmptyError())) } } - alert.addButton(getString(R.string.leave_delete_x_tasks, taskCount), false, true) { _, _ -> + alert.addButton(getString(R.string.leave_delete_x_tasks, taskCount), isPrimary = false, isDestructive = true) { _, _ -> challenge?.let { compositeSubscription.add(challengeRepository.leaveChallenge(it, "remove-all") .flatMap { userRepository.retrieveUser(true) } - .subscribe(Consumer { + .subscribe({ finish() }, RxErrorHandler.handleEmptyError())) } @@ -558,7 +531,7 @@ class TaskFormActivity : BaseActivity() { } companion object { - val SELECTED_TAGS_KEY = "selectedTags" + const val SELECTED_TAGS_KEY = "selectedTags" const val TASK_ID_KEY = "taskId" const val TASK_VALUE_KEY = "taskValue" const val USER_ID_KEY = "userId" diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/VerifyUsernameActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/VerifyUsernameActivity.kt index f5da763a7..ba2a3647f 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/VerifyUsernameActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/VerifyUsernameActivity.kt @@ -5,46 +5,33 @@ import android.graphics.drawable.Drawable import android.os.Bundle import android.text.method.LinkMovementMethod import android.view.View -import android.view.ViewGroup -import android.widget.Button -import android.widget.EditText -import android.widget.TextView import androidx.core.content.ContextCompat import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.databinding.ActivityVerifyUsernameBinding import com.habitrpg.android.habitica.extensions.OnChangeTextWatcher import com.habitrpg.android.habitica.extensions.runDelayed import com.habitrpg.android.habitica.helpers.RxErrorHandler -import com.habitrpg.android.habitica.models.responses.VerifyUsernameResponse -import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar import io.reactivex.BackpressureStrategy import io.reactivex.Flowable -import io.reactivex.functions.BiFunction -import io.reactivex.functions.Consumer import io.reactivex.subjects.PublishSubject import java.util.concurrent.TimeUnit import javax.inject.Inject class VerifyUsernameActivity: BaseActivity() { + private lateinit var binding: ActivityVerifyUsernameBinding + @Inject lateinit var userRepository: UserRepository - private val displayNameEditText: EditText by bindView(R.id.display_name_edit_text) - private val usernameEditText: EditText by bindView(R.id.username_edit_text) - private val confirmUsernameButton: Button by bindView(R.id.confirm_username_button) - private val issuesTextView: TextView by bindView(R.id.issues_text_view) - private val snackbarView: ViewGroup by bindView(R.id.snackbar_view) - private val wikiTextView: TextView by bindView(R.id.wiki_text_view) - private val footerTextView: TextView by bindView(R.id.footer_text_view) - private val displayNameVerificationEvents = PublishSubject.create