diff --git a/app/schemas/org.hackillinois.android.database.Database/6.json b/app/schemas/org.hackillinois.android.database.Database/6.json new file mode 100644 index 000000000..d1d5f828c --- /dev/null +++ b/app/schemas/org.hackillinois.android.database.Database/6.json @@ -0,0 +1,396 @@ +{ + "formatVersion": 1, + "database": { + "version": 6, + "identityHash": "afa24420ee99f9757a10c6b1939437f2", + "entities": [ + { + "tableName": "qr_codes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `qrInfo` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "qrInfo", + "columnName": "qrInfo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "attendees", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `firstName` TEXT NOT NULL, `lastName` TEXT NOT NULL, `dietary` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "firstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "lastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dietary", + "columnName": "dietary", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "users", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "events", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`eventId` TEXT NOT NULL, `name` TEXT NOT NULL, `description` TEXT NOT NULL, `startTime` INTEGER NOT NULL, `endTime` INTEGER NOT NULL, `locations` TEXT NOT NULL, `sponsor` TEXT NOT NULL, `eventType` TEXT NOT NULL, `points` TEXT NOT NULL, `isAsync` INTEGER NOT NULL, `isPrivate` INTEGER NOT NULL, `displayOnStaffCheckIn` INTEGER NOT NULL, PRIMARY KEY(`eventId`))", + "fields": [ + { + "fieldPath": "eventId", + "columnName": "eventId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startTime", + "columnName": "startTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "endTime", + "columnName": "endTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "locations", + "columnName": "locations", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sponsor", + "columnName": "sponsor", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "eventType", + "columnName": "eventType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isAsync", + "columnName": "isAsync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPrivate", + "columnName": "isPrivate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "displayOnStaffCheckIn", + "columnName": "displayOnStaffCheckIn", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "eventId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "roles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roles` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "profiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `displayName` TEXT NOT NULL, `discordTag` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `points` INTEGER NOT NULL, `userId` TEXT NOT NULL, `foodWave` INTEGER NOT NULL, `coins` INTEGER NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "_id", + "columnName": "_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "discordTag", + "columnName": "discordTag", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "foodWave", + "columnName": "foodWave", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "coins", + "columnName": "coins", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "leaderboard", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `displayName` TEXT NOT NULL, `points` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "shop", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`itemId` TEXT NOT NULL, `name` TEXT NOT NULL, `price` INTEGER NOT NULL, `isRaffle` INTEGER NOT NULL, `quantity` INTEGER NOT NULL, `imageURL` TEXT NOT NULL, PRIMARY KEY(`itemId`))", + "fields": [ + { + "fieldPath": "itemId", + "columnName": "itemId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRaffle", + "columnName": "isRaffle", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "quantity", + "columnName": "quantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "imageURL", + "columnName": "imageURL", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "itemId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'afa24420ee99f9757a10c6b1939437f2')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/org.hackillinois.android.database.Database/7.json b/app/schemas/org.hackillinois.android.database.Database/7.json new file mode 100644 index 000000000..4394691ba --- /dev/null +++ b/app/schemas/org.hackillinois.android.database.Database/7.json @@ -0,0 +1,396 @@ +{ + "formatVersion": 1, + "database": { + "version": 7, + "identityHash": "afa24420ee99f9757a10c6b1939437f2", + "entities": [ + { + "tableName": "qr_codes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `qrInfo` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "qrInfo", + "columnName": "qrInfo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "attendees", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `firstName` TEXT NOT NULL, `lastName` TEXT NOT NULL, `dietary` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "firstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "lastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dietary", + "columnName": "dietary", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "users", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "events", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`eventId` TEXT NOT NULL, `name` TEXT NOT NULL, `description` TEXT NOT NULL, `startTime` INTEGER NOT NULL, `endTime` INTEGER NOT NULL, `locations` TEXT NOT NULL, `sponsor` TEXT NOT NULL, `eventType` TEXT NOT NULL, `points` TEXT NOT NULL, `isAsync` INTEGER NOT NULL, `isPrivate` INTEGER NOT NULL, `displayOnStaffCheckIn` INTEGER NOT NULL, PRIMARY KEY(`eventId`))", + "fields": [ + { + "fieldPath": "eventId", + "columnName": "eventId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startTime", + "columnName": "startTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "endTime", + "columnName": "endTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "locations", + "columnName": "locations", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sponsor", + "columnName": "sponsor", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "eventType", + "columnName": "eventType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isAsync", + "columnName": "isAsync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPrivate", + "columnName": "isPrivate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "displayOnStaffCheckIn", + "columnName": "displayOnStaffCheckIn", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "eventId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "roles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roles` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "profiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `displayName` TEXT NOT NULL, `discordTag` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `points` INTEGER NOT NULL, `userId` TEXT NOT NULL, `foodWave` INTEGER NOT NULL, `coins` INTEGER NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "_id", + "columnName": "_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "discordTag", + "columnName": "discordTag", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "foodWave", + "columnName": "foodWave", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "coins", + "columnName": "coins", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "leaderboard", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `displayName` TEXT NOT NULL, `points` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "shop", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`itemId` TEXT NOT NULL, `name` TEXT NOT NULL, `price` INTEGER NOT NULL, `isRaffle` INTEGER NOT NULL, `quantity` INTEGER NOT NULL, `imageURL` TEXT NOT NULL, PRIMARY KEY(`itemId`))", + "fields": [ + { + "fieldPath": "itemId", + "columnName": "itemId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRaffle", + "columnName": "isRaffle", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "quantity", + "columnName": "quantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "imageURL", + "columnName": "imageURL", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "itemId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'afa24420ee99f9757a10c6b1939437f2')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/org.hackillinois.android.database.Database/8.json b/app/schemas/org.hackillinois.android.database.Database/8.json new file mode 100644 index 000000000..35554e57a --- /dev/null +++ b/app/schemas/org.hackillinois.android.database.Database/8.json @@ -0,0 +1,396 @@ +{ + "formatVersion": 1, + "database": { + "version": 8, + "identityHash": "afa24420ee99f9757a10c6b1939437f2", + "entities": [ + { + "tableName": "qr_codes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `qrInfo` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "qrInfo", + "columnName": "qrInfo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "attendees", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `firstName` TEXT NOT NULL, `lastName` TEXT NOT NULL, `dietary` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "firstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "lastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dietary", + "columnName": "dietary", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "users", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "events", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`eventId` TEXT NOT NULL, `name` TEXT NOT NULL, `description` TEXT NOT NULL, `startTime` INTEGER NOT NULL, `endTime` INTEGER NOT NULL, `locations` TEXT NOT NULL, `sponsor` TEXT NOT NULL, `eventType` TEXT NOT NULL, `points` TEXT NOT NULL, `isAsync` INTEGER NOT NULL, `isPrivate` INTEGER NOT NULL, `displayOnStaffCheckIn` INTEGER NOT NULL, PRIMARY KEY(`eventId`))", + "fields": [ + { + "fieldPath": "eventId", + "columnName": "eventId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startTime", + "columnName": "startTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "endTime", + "columnName": "endTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "locations", + "columnName": "locations", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sponsor", + "columnName": "sponsor", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "eventType", + "columnName": "eventType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isAsync", + "columnName": "isAsync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPrivate", + "columnName": "isPrivate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "displayOnStaffCheckIn", + "columnName": "displayOnStaffCheckIn", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "eventId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "roles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roles` TEXT NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "profiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `displayName` TEXT NOT NULL, `discordTag` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `points` INTEGER NOT NULL, `userId` TEXT NOT NULL, `foodWave` INTEGER NOT NULL, `coins` INTEGER NOT NULL, `key` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "_id", + "columnName": "_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "discordTag", + "columnName": "discordTag", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "foodWave", + "columnName": "foodWave", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "coins", + "columnName": "coins", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "leaderboard", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `displayName` TEXT NOT NULL, `points` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "shop", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`itemId` TEXT NOT NULL, `name` TEXT NOT NULL, `price` INTEGER NOT NULL, `isRaffle` INTEGER NOT NULL, `quantity` INTEGER NOT NULL, `imageURL` TEXT NOT NULL, PRIMARY KEY(`itemId`))", + "fields": [ + { + "fieldPath": "itemId", + "columnName": "itemId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRaffle", + "columnName": "isRaffle", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "quantity", + "columnName": "quantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "imageURL", + "columnName": "imageURL", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "itemId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'afa24420ee99f9757a10c6b1939437f2')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/org/hackillinois/android/API.kt b/app/src/main/java/org/hackillinois/android/API.kt index fedc43dd8..e57432dd6 100644 --- a/app/src/main/java/org/hackillinois/android/API.kt +++ b/app/src/main/java/org/hackillinois/android/API.kt @@ -58,6 +58,11 @@ interface API { @GET("registration/attendee/") suspend fun attendee(): Attendee + // SHOP + + @GET("shop/") + suspend fun shop(): List + // STAFF @POST("staff/attendance/") diff --git a/app/src/main/java/org/hackillinois/android/database/Database.kt b/app/src/main/java/org/hackillinois/android/database/Database.kt index 6bf61169b..579f438dd 100644 --- a/app/src/main/java/org/hackillinois/android/database/Database.kt +++ b/app/src/main/java/org/hackillinois/android/database/Database.kt @@ -15,8 +15,9 @@ import org.hackillinois.android.database.entity.Leaderboard Roles::class, Profile::class, Leaderboard::class, + ShopItem::class, ], - version = 5, + version = 8, ) abstract class Database : RoomDatabase() { @@ -27,4 +28,5 @@ abstract class Database : RoomDatabase() { abstract fun rolesDao(): RolesDao abstract fun profileDao(): ProfileDao abstract fun leaderboardDao(): LeaderboardDao + abstract fun shopDao(): ShopDao } diff --git a/app/src/main/java/org/hackillinois/android/database/dao/ShopDao.kt b/app/src/main/java/org/hackillinois/android/database/dao/ShopDao.kt new file mode 100644 index 000000000..c3bb8de84 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/database/dao/ShopDao.kt @@ -0,0 +1,28 @@ +package org.hackillinois.android.database.dao + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Transaction +import org.hackillinois.android.database.entity.ShopItem + +@Dao +interface ShopDao { + + @Query("SELECT * FROM shop") + fun getShop(): LiveData> + + @Query("DELETE FROM shop") + fun clearTable() + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertAll(items: List) + + @Transaction + fun clearTableAndInsertShopItems(items: List) { + clearTable() + insertAll(items) + } +} diff --git a/app/src/main/java/org/hackillinois/android/database/entity/Profile.kt b/app/src/main/java/org/hackillinois/android/database/entity/Profile.kt index ed4742c7c..7a16684d2 100644 --- a/app/src/main/java/org/hackillinois/android/database/entity/Profile.kt +++ b/app/src/main/java/org/hackillinois/android/database/entity/Profile.kt @@ -15,6 +15,7 @@ data class Profile( var points: Int, var userId: String, var foodWave: Int, + var coins: Int, ) { @PrimaryKey var key = 1 diff --git a/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt b/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt new file mode 100644 index 000000000..5111d5609 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/database/entity/ShopItem.kt @@ -0,0 +1,17 @@ +package org.hackillinois.android.database.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.TypeConverters +import org.hackillinois.android.database.Converters + +@Entity(tableName = "shop") +@TypeConverters(Converters::class) +data class ShopItem( + @PrimaryKey val itemId: String, + var name: String, + var price: Int, + var isRaffle: Boolean, + var quantity: Int, + var imageURL: String, +) diff --git a/app/src/main/java/org/hackillinois/android/repository/LeaderboardRepository.kt b/app/src/main/java/org/hackillinois/android/repository/LeaderboardRepository.kt index 6dff80dbe..bb8d60c65 100644 --- a/app/src/main/java/org/hackillinois/android/repository/LeaderboardRepository.kt +++ b/app/src/main/java/org/hackillinois/android/repository/LeaderboardRepository.kt @@ -15,6 +15,7 @@ class LeaderboardRepository { fun fetchLeaderboard(): LiveData> { // 'refreshAll()' coroutine is called only when leaderboard button on bottom app bar clicked refreshAll() + // locally stored database val lb = leaderboardDao.getLeaderboard() Log.d("LEADERBOARD CALL", lb.value.toString()) return lb diff --git a/app/src/main/java/org/hackillinois/android/repository/ShopRepository.kt b/app/src/main/java/org/hackillinois/android/repository/ShopRepository.kt new file mode 100644 index 000000000..a3c106555 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/repository/ShopRepository.kt @@ -0,0 +1,39 @@ +package org.hackillinois.android.repository + +import android.util.Log +import androidx.lifecycle.LiveData +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import org.hackillinois.android.App +import org.hackillinois.android.database.entity.ShopItem +import java.lang.Exception + +class ShopRepository { + private val shopDao = App.database.shopDao() + + fun fetchShop(): LiveData> { + // 'refreshAll()' coroutine is called only when shop button on bottom app bar clicked + refreshAll() + // locally stored database + val lb = shopDao.getShop() + Log.d("SHOP CALL", lb.value.toString()) + return lb + } + + fun refreshAll() { + GlobalScope.launch(Dispatchers.IO) { + try { + val shop = App.getAPI().shop() + Log.d("SHOP REFRESH ALL", shop.toString()) + shopDao.clearTableAndInsertShopItems(shop) + } catch (e: Exception) { + Log.e("SHOP REFRESH ALL", e.toString()) + } + } + } + + companion object { + val instance: ShopRepository by lazy { ShopRepository() } + } +} diff --git a/app/src/main/java/org/hackillinois/android/view/MainActivity.kt b/app/src/main/java/org/hackillinois/android/view/MainActivity.kt index 404c9c482..1d18a3def 100644 --- a/app/src/main/java/org/hackillinois/android/view/MainActivity.kt +++ b/app/src/main/java/org/hackillinois/android/view/MainActivity.kt @@ -23,11 +23,11 @@ import org.hackillinois.android.common.FavoritesManager import org.hackillinois.android.common.JWTUtilities import org.hackillinois.android.notifications.FirebaseTokenManager import org.hackillinois.android.view.home.HomeFragment -import org.hackillinois.android.view.leaderboard.LeaderboardFragment import org.hackillinois.android.view.profile.ProfileFragment import org.hackillinois.android.view.scanner.ScannerFragment import org.hackillinois.android.view.scanner.StaffScannerFragment import org.hackillinois.android.view.schedule.ScheduleFragment +import org.hackillinois.android.view.shop.ShopFragment import org.hackillinois.android.viewmodel.MainViewModel import kotlin.concurrent.thread @@ -66,8 +66,8 @@ class MainActivity : AppCompatActivity() { val bottomBarButtons = listOf( bottomAppBar.homeButton, bottomAppBar.scheduleButton, - bottomAppBar.shop, - bottomAppBar.profile, + bottomAppBar.shopButton, + bottomAppBar.profileButton, ) // make all buttons unselectedColor and then set selected button to selectedColor @@ -87,8 +87,8 @@ class MainActivity : AppCompatActivity() { when (view) { bottomAppBar.homeButton -> switchFragment(HomeFragment(), false) bottomAppBar.scheduleButton -> switchFragment(ScheduleFragment(), false) - bottomAppBar.shop -> switchFragment(LeaderboardFragment(), false) - bottomAppBar.profile -> switchFragment(ProfileFragment(), false) + bottomAppBar.shopButton -> switchFragment(ShopFragment(), false) + bottomAppBar.profileButton -> switchFragment(ProfileFragment(), false) else -> return@setOnClickListener } } @@ -110,8 +110,8 @@ class MainActivity : AppCompatActivity() { val bottomBarButtons = listOf( bottomAppBar.homeButton, bottomAppBar.scheduleButton, - bottomAppBar.shop, - bottomAppBar.profile, + bottomAppBar.shopButton, + bottomAppBar.profileButton, ) val unselectedIconColor = ContextCompat.getColor(this, R.color.unselectedAppBarIcon) bottomBarButtons.forEach { (it as ImageButton).setColorFilter(unselectedIconColor) } diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt new file mode 100644 index 000000000..cae359555 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopAdapter.kt @@ -0,0 +1,72 @@ +package org.hackillinois.android.view.shop + +import android.content.Context +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import kotlinx.android.synthetic.main.shop_tile.view.* +import org.hackillinois.android.R +import org.hackillinois.android.database.entity.ShopItem +import java.lang.Exception + +class ShopAdapter(private var itemList: List) : + RecyclerView.Adapter() { + private lateinit var context: Context + inner class ViewHolder(parent: View) : RecyclerView.ViewHolder(parent) + + // onCreateViewHolder used to display scrollable list of items + // implemented as part of RecyclerView's adapter, responsible for creating new ViewHolder objects + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val layoutResource = R.layout.shop_tile + val view = LayoutInflater.from(parent.context).inflate(layoutResource, parent, false) + val viewHolder = ViewHolder(view) + context = parent.context + return viewHolder + } + + override fun getItemCount() = itemList.size + + // onBindViewHolder called when ViewHolder needs to be filled with data + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val item = itemList[position] + // populating views within ViewHolder with data from 'item' + // position is zero-indexed but we want the leaderboard to start at 1 + bind(item, holder.itemView, position + 1) + } + + private fun bind(item: ShopItem, itemView: View, position: Int) { + itemView.apply { + // set the top brown divider for the first item to be visible + if (position == 1) { + val topDivider: TextView = itemView.findViewById(R.id.brownDividerTop) + topDivider.visibility = View.VISIBLE + } else { + val topDivider: TextView = itemView.findViewById(R.id.brownDividerTop) + topDivider.visibility = View.GONE + } + + shopItemTextView.text = item.name + priceTextView.text = item.price.toString() + + val quantity = item.quantity + quantityTextView.text = resources.getString(R.string.shopquantity, quantity) + + val shopItemImageView: ImageView = itemView.findViewById(R.id.shopItemImageView) + try { + Glide.with(context).load(item.imageURL).into(shopItemImageView) + } catch (e: Exception) { + Log.d("Shop Glide Error", e.message.toString()) + } + } + } + + fun updateShop(shopItem: List) { + this.itemList = shopItem + notifyDataSetChanged() + } +} diff --git a/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt new file mode 100644 index 000000000..6050d0b27 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/view/shop/ShopFragment.kt @@ -0,0 +1,159 @@ +package org.hackillinois.android.view.shop + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.fragment_point_shop.coin_total_textview +import kotlinx.android.synthetic.main.fragment_point_shop.view.recyclerview_point_shop +import org.hackillinois.android.R +import org.hackillinois.android.common.JWTUtilities +import org.hackillinois.android.database.entity.Profile +import org.hackillinois.android.database.entity.ShopItem +import org.hackillinois.android.viewmodel.ShopViewModel + +class ShopFragment : Fragment() { + + companion object { + fun newInstance() = ShopFragment() + } + + private lateinit var shopViewModel: ShopViewModel + private var shop: List = listOf() + private lateinit var recyclerView: RecyclerView + private lateinit var mLayoutManager: LinearLayoutManager + private lateinit var mAdapter: ShopAdapter + + private lateinit var merchButton: TextView + private lateinit var raffleButton: TextView + + private var merchItems: List = listOf() + private var raffleItems: List = listOf() + + // Merch tab is default selected + private var showingMerch: Boolean = true + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + shopViewModel = ViewModelProvider(this).get(ShopViewModel::class.java) + + // pass whether the user is an attendee to the viewmodel + if (hasLoggedIn() && isAttendee()) { + shopViewModel.init(true) + } else { + shopViewModel.init(false) + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.fragment_point_shop, container, false) + + merchButton = view.findViewById(R.id.merchButton) + raffleButton = view.findViewById(R.id.raffleButton) + + mAdapter = ShopAdapter(shop) + + recyclerView = view.recyclerview_point_shop.apply { + mLayoutManager = LinearLayoutManager(context) + this.layoutManager = mLayoutManager + this.adapter = mAdapter + } + + shopViewModel.shopLiveData.observe( + viewLifecycleOwner, + Observer { + // will split shop items into Merch or Raffle category + updateShopItems(it) + }, + ) + + merchButton.setOnClickListener(merchClickListener) + raffleButton.setOnClickListener(raffleClickListener) + + if (hasLoggedIn() && isAttendee()) { + // set coin views visible for attendee + val coinBg: TextView = view.findViewById(R.id.total_coin_view) + val coinText: TextView = view.findViewById(R.id.coin_total_textview) + val coinImg: ImageView = view.findViewById(R.id.coin_imageview) + coinBg.visibility = View.VISIBLE + coinText.visibility = View.VISIBLE + coinImg.visibility = View.VISIBLE + + shopViewModel.profileLiveData.observe( + viewLifecycleOwner, + Observer { + updateCoinTotalUI(it) + }, + ) + } + + return view + } + + // Called in onCreateView within shopLiveData.observe + private fun updateShopItems(newShop: List) { + // Split the shop items into Merch and Raffle items + merchItems = newShop.filter { !it.isRaffle } + raffleItems = newShop.filter { it.isRaffle } + + // Update the UI based on the selected button + updateShopUI() + } + + private fun updateShopUI() { + // if showingMerch variable is True based on selected button, show merch items. else, show raffle + val itemsToShow = if (showingMerch) merchItems else raffleItems + mAdapter.updateShop(itemsToShow) + } + + // update merch ViewModel on click + private val merchClickListener = View.OnClickListener { + if (!merchButton.isSelected) { + merchButton.isSelected = true + merchButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.shop_selected_tab) } + raffleButton.isSelected = false + raffleButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.shop_unselected_tab) } + showingMerch = true + updateShopUI() + } + } + + // update raffle ViewModel on click + private val raffleClickListener = View.OnClickListener { + if (!raffleButton.isSelected) { + raffleButton.isSelected = true + raffleButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.shop_selected_tab) } + merchButton.isSelected = false + merchButton.background = this.context?.let { it1 -> ContextCompat.getDrawable(it1, R.drawable.shop_unselected_tab) } + showingMerch = false + updateShopUI() + } + } + + private fun updateCoinTotalUI(newProfile: Profile?) { + if (newProfile != null) { + coin_total_textview.text = String.format("%,d", newProfile.coins) + } + } + + private fun hasLoggedIn(): Boolean { + // Reads JWT and checks if it is equal to an empty JWT + return JWTUtilities.readJWT(requireActivity().applicationContext) != JWTUtilities.DEFAULT_JWT + } + + private fun isAttendee(): Boolean { + val context = requireActivity().applicationContext + val prefString = context.getString(R.string.authorization_pref_file_key) + return context.getSharedPreferences(prefString, Context.MODE_PRIVATE).getString("provider", "") ?: "" == "github" + } +} diff --git a/app/src/main/java/org/hackillinois/android/viewmodel/ShopViewModel.kt b/app/src/main/java/org/hackillinois/android/viewmodel/ShopViewModel.kt new file mode 100644 index 000000000..93dd98516 --- /dev/null +++ b/app/src/main/java/org/hackillinois/android/viewmodel/ShopViewModel.kt @@ -0,0 +1,45 @@ +package org.hackillinois.android.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.ViewModel +import org.hackillinois.android.database.entity.Profile +import org.hackillinois.android.database.entity.ShopItem +import org.hackillinois.android.repository.ProfileRepository +import org.hackillinois.android.repository.ShopRepository +import java.util.Timer +import java.util.TimerTask + +class ShopViewModel : ViewModel() { + private val shopRepository = ShopRepository.instance + private val profileRepository = ProfileRepository.instance + + lateinit var shopLiveData: LiveData> + lateinit var profileLiveData: LiveData + + lateinit var timerObj: Timer + + fun init(isAttendee: Boolean) { + // initial fetch + shopLiveData = shopRepository.fetchShop() + if (isAttendee) { + profileLiveData = profileRepository.fetchProfile() + } + + // runs TimerTask every 10 seconds to fetch profile and shop data + timerObj = Timer() + val timerTaskObj: TimerTask = object : TimerTask() { + override fun run() { + shopLiveData = shopRepository.fetchShop() + if (isAttendee) { + profileLiveData = profileRepository.fetchProfile() + } + } + } + timerObj.scheduleAtFixedRate(timerTaskObj, 0, 10000) + } + + override fun onCleared() { + super.onCleared() + timerObj.cancel() + } +} diff --git a/app/src/main/res/drawable/coin.xml b/app/src/main/res/drawable/coin.xml new file mode 100644 index 000000000..bf8f2ff11 --- /dev/null +++ b/app/src/main/res/drawable/coin.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/faded_coin.xml b/app/src/main/res/drawable/faded_coin.xml new file mode 100644 index 000000000..55fe21019 --- /dev/null +++ b/app/src/main/res/drawable/faded_coin.xml @@ -0,0 +1,33 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_banner.xml b/app/src/main/res/drawable/point_shop_banner.xml new file mode 100644 index 000000000..53331eafd --- /dev/null +++ b/app/src/main/res/drawable/point_shop_banner.xml @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_bg.xml b/app/src/main/res/drawable/point_shop_bg.xml new file mode 100644 index 000000000..ddf93798c --- /dev/null +++ b/app/src/main/res/drawable/point_shop_bg.xml @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/point_shop_divider.xml b/app/src/main/res/drawable/point_shop_divider.xml new file mode 100644 index 000000000..85fa04f42 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_divider.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/point_shop_tile_bg.xml b/app/src/main/res/drawable/point_shop_tile_bg.xml new file mode 100644 index 000000000..7d567c433 --- /dev/null +++ b/app/src/main/res/drawable/point_shop_tile_bg.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_coin_total_bg.xml b/app/src/main/res/drawable/rounded_coin_total_bg.xml new file mode 100644 index 000000000..0987c48db --- /dev/null +++ b/app/src/main/res/drawable/rounded_coin_total_bg.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/drawable/rounded_dark_forest_bg.xml b/app/src/main/res/drawable/rounded_dark_forest_bg.xml new file mode 100644 index 000000000..4dc5229e1 --- /dev/null +++ b/app/src/main/res/drawable/rounded_dark_forest_bg.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/drawable/shop_potion_sticker.xml b/app/src/main/res/drawable/shop_potion_sticker.xml new file mode 100644 index 000000000..af0f709c9 --- /dev/null +++ b/app/src/main/res/drawable/shop_potion_sticker.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/shop_selected_tab.xml b/app/src/main/res/drawable/shop_selected_tab.xml new file mode 100644 index 000000000..bf6a75890 --- /dev/null +++ b/app/src/main/res/drawable/shop_selected_tab.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shop_unselected_tab.xml b/app/src/main/res/drawable/shop_unselected_tab.xml new file mode 100644 index 000000000..93aaeccf2 --- /dev/null +++ b/app/src/main/res/drawable/shop_unselected_tab.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 584fa33bf..5d2edf006 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -49,28 +49,28 @@ android:layout_height="0dp" android:visibility="invisible" app:layout_constraintBottom_toBottomOf="@id/homeButton" - app:layout_constraintEnd_toStartOf="@id/shop" + app:layout_constraintEnd_toStartOf="@id/shopButton" app:layout_constraintStart_toEndOf="@id/scheduleButton" app:layout_constraintTop_toTopOf="@id/homeButton" /> diff --git a/app/src/main/res/layout/fragment_leaderboard.xml b/app/src/main/res/layout/fragment_leaderboard.xml index 21e5d5fa9..44f54f9f6 100644 --- a/app/src/main/res/layout/fragment_leaderboard.xml +++ b/app/src/main/res/layout/fragment_leaderboard.xml @@ -34,7 +34,7 @@ android:fontFamily="@font/montserrat_bold" android:textColor="@color/white" android:text="@string/leaderboard" - /> + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/shop_tile.xml b/app/src/main/res/layout/shop_tile.xml new file mode 100644 index 000000000..d01731ce2 --- /dev/null +++ b/app/src/main/res/layout/shop_tile.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 7f4e77120..9bb7cb7e3 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,6 +3,7 @@ #FFFFFF + #66FFFFFF #A5DAD5 #d7d4b8 #212121 @@ -44,6 +45,7 @@ #A5DAD5 #ACCEBE #0D3F41 + #800D3F41 #A61E00 #964C1A #662B13 @@ -60,6 +62,8 @@ #FFC95B #84BCB9 #C62A6C + #2A2A2A + #D84177 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 00ac1477f..df9169835 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -66,6 +66,14 @@ %d pts + + POINT SHOP + %d Left + --- + | + MERCH + RAFFLE + PROFILE Dietary Restrictions @@ -87,4 +95,5 @@ You must log in to use this feature! Go to the Profile tab to logout. +