Merge branch 'arrange_tabs' into 'master'
Rearrange tabs See merge request pixeldroid/PixelDroid!570
This commit is contained in:
commit
34d2a8c581
|
@ -50,6 +50,9 @@ android {
|
|||
versionName "1.0.beta" + versionCode
|
||||
|
||||
//TODO add resConfigs("en", "fr", "ja",...) ?
|
||||
ksp {
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
}
|
||||
|
||||
testInstrumentationRunner "org.pixeldroid.app.testUtility.TestRunner"
|
||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||
|
|
|
@ -0,0 +1,710 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 6,
|
||||
"identityHash": "365491e03fadf81e596b11716640518c",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "instances",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `title` TEXT NOT NULL, `maxStatusChars` INTEGER NOT NULL, `maxPhotoSize` INTEGER NOT NULL, `maxVideoSize` INTEGER NOT NULL, `albumLimit` INTEGER NOT NULL, `videoEnabled` INTEGER NOT NULL, `pixelfed` INTEGER NOT NULL, PRIMARY KEY(`uri`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "uri",
|
||||
"columnName": "uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "maxStatusChars",
|
||||
"columnName": "maxStatusChars",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "maxPhotoSize",
|
||||
"columnName": "maxPhotoSize",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "maxVideoSize",
|
||||
"columnName": "maxVideoSize",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "albumLimit",
|
||||
"columnName": "albumLimit",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "videoEnabled",
|
||||
"columnName": "videoEnabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "pixelfed",
|
||||
"columnName": "pixelfed",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"uri"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "users",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `instance_uri` TEXT NOT NULL, `username` TEXT NOT NULL, `display_name` TEXT NOT NULL, `avatar_static` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accessToken` TEXT NOT NULL, `refreshToken` TEXT, `clientId` TEXT NOT NULL, `clientSecret` TEXT NOT NULL, PRIMARY KEY(`user_id`, `instance_uri`), FOREIGN KEY(`instance_uri`) REFERENCES `instances`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "user_id",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "instance_uri",
|
||||
"columnName": "instance_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "username",
|
||||
"columnName": "username",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "display_name",
|
||||
"columnName": "display_name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "avatar_static",
|
||||
"columnName": "avatar_static",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isActive",
|
||||
"columnName": "isActive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accessToken",
|
||||
"columnName": "accessToken",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "refreshToken",
|
||||
"columnName": "refreshToken",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "clientId",
|
||||
"columnName": "clientId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "clientSecret",
|
||||
"columnName": "clientSecret",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_users_instance_uri",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"instance_uri"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_users_instance_uri` ON `${TABLE_NAME}` (`instance_uri`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "instances",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "CASCADE",
|
||||
"columns": [
|
||||
"instance_uri"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"uri"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "homePosts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `instance_uri` TEXT NOT NULL, `id` TEXT NOT NULL, `uri` TEXT, `created_at` TEXT, `account` TEXT, `content` TEXT, `visibility` TEXT, `sensitive` INTEGER, `spoiler_text` TEXT, `media_attachments` TEXT, `application` TEXT, `mentions` TEXT, `tags` TEXT, `emojis` TEXT, `reblogs_count` INTEGER, `favourites_count` INTEGER, `replies_count` INTEGER, `url` TEXT, `in_reply_to_id` TEXT, `in_reply_to_account` TEXT, `reblog` TEXT, `poll` TEXT, `card` TEXT, `language` TEXT, `text` TEXT, `favourited` INTEGER, `reblogged` INTEGER, `muted` INTEGER, `bookmarked` INTEGER, `pinned` INTEGER, PRIMARY KEY(`id`, `user_id`, `instance_uri`), FOREIGN KEY(`user_id`, `instance_uri`) REFERENCES `users`(`user_id`, `instance_uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "user_id",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "instance_uri",
|
||||
"columnName": "instance_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "uri",
|
||||
"columnName": "uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "created_at",
|
||||
"columnName": "created_at",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "account",
|
||||
"columnName": "account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "visibility",
|
||||
"columnName": "visibility",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "sensitive",
|
||||
"columnName": "sensitive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "spoiler_text",
|
||||
"columnName": "spoiler_text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "media_attachments",
|
||||
"columnName": "media_attachments",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "application",
|
||||
"columnName": "application",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "mentions",
|
||||
"columnName": "mentions",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "tags",
|
||||
"columnName": "tags",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "emojis",
|
||||
"columnName": "emojis",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogs_count",
|
||||
"columnName": "reblogs_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "favourites_count",
|
||||
"columnName": "favourites_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "replies_count",
|
||||
"columnName": "replies_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "in_reply_to_id",
|
||||
"columnName": "in_reply_to_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "in_reply_to_account",
|
||||
"columnName": "in_reply_to_account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblog",
|
||||
"columnName": "reblog",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "poll",
|
||||
"columnName": "poll",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "card",
|
||||
"columnName": "card",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "language",
|
||||
"columnName": "language",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "text",
|
||||
"columnName": "text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "favourited",
|
||||
"columnName": "favourited",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogged",
|
||||
"columnName": "reblogged",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "muted",
|
||||
"columnName": "muted",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "bookmarked",
|
||||
"columnName": "bookmarked",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "pinned",
|
||||
"columnName": "pinned",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id",
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_homePosts_user_id_instance_uri",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_homePosts_user_id_instance_uri` ON `${TABLE_NAME}` (`user_id`, `instance_uri`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "users",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "CASCADE",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "publicPosts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `instance_uri` TEXT NOT NULL, `id` TEXT NOT NULL, `uri` TEXT, `created_at` TEXT, `account` TEXT, `content` TEXT, `visibility` TEXT, `sensitive` INTEGER, `spoiler_text` TEXT, `media_attachments` TEXT, `application` TEXT, `mentions` TEXT, `tags` TEXT, `emojis` TEXT, `reblogs_count` INTEGER, `favourites_count` INTEGER, `replies_count` INTEGER, `url` TEXT, `in_reply_to_id` TEXT, `in_reply_to_account` TEXT, `reblog` TEXT, `poll` TEXT, `card` TEXT, `language` TEXT, `text` TEXT, `favourited` INTEGER, `reblogged` INTEGER, `muted` INTEGER, `bookmarked` INTEGER, `pinned` INTEGER, PRIMARY KEY(`id`, `user_id`, `instance_uri`), FOREIGN KEY(`user_id`, `instance_uri`) REFERENCES `users`(`user_id`, `instance_uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "user_id",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "instance_uri",
|
||||
"columnName": "instance_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "uri",
|
||||
"columnName": "uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "created_at",
|
||||
"columnName": "created_at",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "account",
|
||||
"columnName": "account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "visibility",
|
||||
"columnName": "visibility",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "sensitive",
|
||||
"columnName": "sensitive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "spoiler_text",
|
||||
"columnName": "spoiler_text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "media_attachments",
|
||||
"columnName": "media_attachments",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "application",
|
||||
"columnName": "application",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "mentions",
|
||||
"columnName": "mentions",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "tags",
|
||||
"columnName": "tags",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "emojis",
|
||||
"columnName": "emojis",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogs_count",
|
||||
"columnName": "reblogs_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "favourites_count",
|
||||
"columnName": "favourites_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "replies_count",
|
||||
"columnName": "replies_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "in_reply_to_id",
|
||||
"columnName": "in_reply_to_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "in_reply_to_account",
|
||||
"columnName": "in_reply_to_account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblog",
|
||||
"columnName": "reblog",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "poll",
|
||||
"columnName": "poll",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "card",
|
||||
"columnName": "card",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "language",
|
||||
"columnName": "language",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "text",
|
||||
"columnName": "text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "favourited",
|
||||
"columnName": "favourited",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogged",
|
||||
"columnName": "reblogged",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "muted",
|
||||
"columnName": "muted",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "bookmarked",
|
||||
"columnName": "bookmarked",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "pinned",
|
||||
"columnName": "pinned",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id",
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_publicPosts_user_id_instance_uri",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_publicPosts_user_id_instance_uri` ON `${TABLE_NAME}` (`user_id`, `instance_uri`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "users",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "CASCADE",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "notifications",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` TEXT, `created_at` TEXT, `account` TEXT, `status` TEXT, `user_id` TEXT NOT NULL, `instance_uri` TEXT NOT NULL, PRIMARY KEY(`id`, `user_id`, `instance_uri`), FOREIGN KEY(`user_id`, `instance_uri`) REFERENCES `users`(`user_id`, `instance_uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "created_at",
|
||||
"columnName": "created_at",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "account",
|
||||
"columnName": "account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "status",
|
||||
"columnName": "status",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "user_id",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "instance_uri",
|
||||
"columnName": "instance_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id",
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_notifications_user_id_instance_uri",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_notifications_user_id_instance_uri` ON `${TABLE_NAME}` (`user_id`, `instance_uri`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "users",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "CASCADE",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"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, '365491e03fadf81e596b11716640518c')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,781 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 7,
|
||||
"identityHash": "cd0310b10eff0e3e961b3cd7a8172b81",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "instances",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uri` TEXT NOT NULL, `title` TEXT NOT NULL, `maxStatusChars` INTEGER NOT NULL, `maxPhotoSize` INTEGER NOT NULL, `maxVideoSize` INTEGER NOT NULL, `albumLimit` INTEGER NOT NULL, `videoEnabled` INTEGER NOT NULL, `pixelfed` INTEGER NOT NULL, PRIMARY KEY(`uri`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "uri",
|
||||
"columnName": "uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "title",
|
||||
"columnName": "title",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "maxStatusChars",
|
||||
"columnName": "maxStatusChars",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "maxPhotoSize",
|
||||
"columnName": "maxPhotoSize",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "maxVideoSize",
|
||||
"columnName": "maxVideoSize",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "albumLimit",
|
||||
"columnName": "albumLimit",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "videoEnabled",
|
||||
"columnName": "videoEnabled",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "pixelfed",
|
||||
"columnName": "pixelfed",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"uri"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "users",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `instance_uri` TEXT NOT NULL, `username` TEXT NOT NULL, `display_name` TEXT NOT NULL, `avatar_static` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accessToken` TEXT NOT NULL, `refreshToken` TEXT, `clientId` TEXT NOT NULL, `clientSecret` TEXT NOT NULL, PRIMARY KEY(`user_id`, `instance_uri`), FOREIGN KEY(`instance_uri`) REFERENCES `instances`(`uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "user_id",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "instance_uri",
|
||||
"columnName": "instance_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "username",
|
||||
"columnName": "username",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "display_name",
|
||||
"columnName": "display_name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "avatar_static",
|
||||
"columnName": "avatar_static",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isActive",
|
||||
"columnName": "isActive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accessToken",
|
||||
"columnName": "accessToken",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "refreshToken",
|
||||
"columnName": "refreshToken",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "clientId",
|
||||
"columnName": "clientId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "clientSecret",
|
||||
"columnName": "clientSecret",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_users_instance_uri",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"instance_uri"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_users_instance_uri` ON `${TABLE_NAME}` (`instance_uri`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "instances",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "CASCADE",
|
||||
"columns": [
|
||||
"instance_uri"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"uri"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "homePosts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `instance_uri` TEXT NOT NULL, `id` TEXT NOT NULL, `uri` TEXT, `created_at` TEXT, `account` TEXT, `content` TEXT, `visibility` TEXT, `sensitive` INTEGER, `spoiler_text` TEXT, `media_attachments` TEXT, `application` TEXT, `mentions` TEXT, `tags` TEXT, `emojis` TEXT, `reblogs_count` INTEGER, `favourites_count` INTEGER, `replies_count` INTEGER, `url` TEXT, `in_reply_to_id` TEXT, `in_reply_to_account` TEXT, `reblog` TEXT, `poll` TEXT, `card` TEXT, `language` TEXT, `text` TEXT, `favourited` INTEGER, `reblogged` INTEGER, `muted` INTEGER, `bookmarked` INTEGER, `pinned` INTEGER, PRIMARY KEY(`id`, `user_id`, `instance_uri`), FOREIGN KEY(`user_id`, `instance_uri`) REFERENCES `users`(`user_id`, `instance_uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "user_id",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "instance_uri",
|
||||
"columnName": "instance_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "uri",
|
||||
"columnName": "uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "created_at",
|
||||
"columnName": "created_at",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "account",
|
||||
"columnName": "account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "visibility",
|
||||
"columnName": "visibility",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "sensitive",
|
||||
"columnName": "sensitive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "spoiler_text",
|
||||
"columnName": "spoiler_text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "media_attachments",
|
||||
"columnName": "media_attachments",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "application",
|
||||
"columnName": "application",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "mentions",
|
||||
"columnName": "mentions",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "tags",
|
||||
"columnName": "tags",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "emojis",
|
||||
"columnName": "emojis",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogs_count",
|
||||
"columnName": "reblogs_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "favourites_count",
|
||||
"columnName": "favourites_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "replies_count",
|
||||
"columnName": "replies_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "in_reply_to_id",
|
||||
"columnName": "in_reply_to_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "in_reply_to_account",
|
||||
"columnName": "in_reply_to_account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblog",
|
||||
"columnName": "reblog",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "poll",
|
||||
"columnName": "poll",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "card",
|
||||
"columnName": "card",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "language",
|
||||
"columnName": "language",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "text",
|
||||
"columnName": "text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "favourited",
|
||||
"columnName": "favourited",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogged",
|
||||
"columnName": "reblogged",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "muted",
|
||||
"columnName": "muted",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "bookmarked",
|
||||
"columnName": "bookmarked",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "pinned",
|
||||
"columnName": "pinned",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id",
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_homePosts_user_id_instance_uri",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_homePosts_user_id_instance_uri` ON `${TABLE_NAME}` (`user_id`, `instance_uri`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "users",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "CASCADE",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "publicPosts",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `instance_uri` TEXT NOT NULL, `id` TEXT NOT NULL, `uri` TEXT, `created_at` TEXT, `account` TEXT, `content` TEXT, `visibility` TEXT, `sensitive` INTEGER, `spoiler_text` TEXT, `media_attachments` TEXT, `application` TEXT, `mentions` TEXT, `tags` TEXT, `emojis` TEXT, `reblogs_count` INTEGER, `favourites_count` INTEGER, `replies_count` INTEGER, `url` TEXT, `in_reply_to_id` TEXT, `in_reply_to_account` TEXT, `reblog` TEXT, `poll` TEXT, `card` TEXT, `language` TEXT, `text` TEXT, `favourited` INTEGER, `reblogged` INTEGER, `muted` INTEGER, `bookmarked` INTEGER, `pinned` INTEGER, PRIMARY KEY(`id`, `user_id`, `instance_uri`), FOREIGN KEY(`user_id`, `instance_uri`) REFERENCES `users`(`user_id`, `instance_uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "user_id",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "instance_uri",
|
||||
"columnName": "instance_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "uri",
|
||||
"columnName": "uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "created_at",
|
||||
"columnName": "created_at",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "account",
|
||||
"columnName": "account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "content",
|
||||
"columnName": "content",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "visibility",
|
||||
"columnName": "visibility",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "sensitive",
|
||||
"columnName": "sensitive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "spoiler_text",
|
||||
"columnName": "spoiler_text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "media_attachments",
|
||||
"columnName": "media_attachments",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "application",
|
||||
"columnName": "application",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "mentions",
|
||||
"columnName": "mentions",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "tags",
|
||||
"columnName": "tags",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "emojis",
|
||||
"columnName": "emojis",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogs_count",
|
||||
"columnName": "reblogs_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "favourites_count",
|
||||
"columnName": "favourites_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "replies_count",
|
||||
"columnName": "replies_count",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "in_reply_to_id",
|
||||
"columnName": "in_reply_to_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "in_reply_to_account",
|
||||
"columnName": "in_reply_to_account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblog",
|
||||
"columnName": "reblog",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "poll",
|
||||
"columnName": "poll",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "card",
|
||||
"columnName": "card",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "language",
|
||||
"columnName": "language",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "text",
|
||||
"columnName": "text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "favourited",
|
||||
"columnName": "favourited",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "reblogged",
|
||||
"columnName": "reblogged",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "muted",
|
||||
"columnName": "muted",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "bookmarked",
|
||||
"columnName": "bookmarked",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "pinned",
|
||||
"columnName": "pinned",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id",
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_publicPosts_user_id_instance_uri",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_publicPosts_user_id_instance_uri` ON `${TABLE_NAME}` (`user_id`, `instance_uri`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "users",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "CASCADE",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "notifications",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `type` TEXT, `created_at` TEXT, `account` TEXT, `status` TEXT, `user_id` TEXT NOT NULL, `instance_uri` TEXT NOT NULL, PRIMARY KEY(`id`, `user_id`, `instance_uri`), FOREIGN KEY(`user_id`, `instance_uri`) REFERENCES `users`(`user_id`, `instance_uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "created_at",
|
||||
"columnName": "created_at",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "account",
|
||||
"columnName": "account",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "status",
|
||||
"columnName": "status",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "user_id",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "instance_uri",
|
||||
"columnName": "instance_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id",
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_notifications_user_id_instance_uri",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_notifications_user_id_instance_uri` ON `${TABLE_NAME}` (`user_id`, `instance_uri`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "users",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "CASCADE",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "tabsChecked",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`index` INTEGER NOT NULL, `user_id` TEXT NOT NULL, `instance_uri` TEXT NOT NULL, `tab` TEXT NOT NULL, `checked` INTEGER NOT NULL, PRIMARY KEY(`index`, `user_id`, `instance_uri`), FOREIGN KEY(`user_id`, `instance_uri`) REFERENCES `users`(`user_id`, `instance_uri`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "index",
|
||||
"columnName": "index",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "user_id",
|
||||
"columnName": "user_id",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "instance_uri",
|
||||
"columnName": "instance_uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "tab",
|
||||
"columnName": "tab",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "checked",
|
||||
"columnName": "checked",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"index",
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_tabsChecked_user_id_instance_uri",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_tabsChecked_user_id_instance_uri` ON `${TABLE_NAME}` (`user_id`, `instance_uri`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "users",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "CASCADE",
|
||||
"columns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"user_id",
|
||||
"instance_uri"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"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, 'cd0310b10eff0e3e961b3cd7a8172b81')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import android.net.Uri
|
|||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
|
@ -23,6 +24,9 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.get
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.marginEnd
|
||||
import androidx.core.view.marginTop
|
||||
import androidx.fragment.app.Fragment
|
||||
|
@ -37,6 +41,7 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
|
|||
import androidx.viewpager2.widget.ViewPager2
|
||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import com.google.android.material.navigation.NavigationBarView
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
|
@ -67,12 +72,15 @@ import org.pixeldroid.app.profile.ProfileActivity
|
|||
import org.pixeldroid.app.searchDiscover.SearchDiscoverFragment
|
||||
import org.pixeldroid.app.settings.SettingsActivity
|
||||
import org.pixeldroid.app.utils.BaseActivity
|
||||
import org.pixeldroid.app.utils.Tab
|
||||
import org.pixeldroid.app.utils.api.objects.Notification
|
||||
import org.pixeldroid.app.utils.db.entities.HomeStatusDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.entities.PublicFeedStatusDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.updateUserInfoDb
|
||||
import org.pixeldroid.app.utils.hasInternet
|
||||
import org.pixeldroid.app.utils.loadDefaultMenuTabs
|
||||
import org.pixeldroid.app.utils.loadDbMenuTabs
|
||||
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker.Companion.INSTANCE_NOTIFICATION_TAG
|
||||
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker.Companion.SHOW_NOTIFICATION_TAG
|
||||
import org.pixeldroid.app.utils.notificationsWorker.NotificationsWorker.Companion.USER_NOTIFICATION_TAG
|
||||
|
@ -95,7 +103,6 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
installSplashScreen().setOnExitAnimationListener {
|
||||
it.remove()
|
||||
|
@ -121,24 +128,8 @@ class MainActivity : BaseActivity() {
|
|||
sendTraceDroidStackTracesIfExist("contact@pixeldroid.org", this)
|
||||
|
||||
setupDrawer()
|
||||
val tabs: List<() -> Fragment> = listOf(
|
||||
{
|
||||
PostFeedFragment<HomeStatusDatabaseEntity>()
|
||||
.apply {
|
||||
arguments = Bundle().apply { putBoolean("home", true) }
|
||||
}
|
||||
},
|
||||
{ SearchDiscoverFragment() },
|
||||
{ CameraFragment() },
|
||||
{ NotificationsFragment() },
|
||||
{
|
||||
PostFeedFragment<PublicFeedStatusDatabaseEntity>()
|
||||
.apply {
|
||||
arguments = Bundle().apply { putBoolean("home", false) }
|
||||
}
|
||||
}
|
||||
)
|
||||
setupTabs(tabs)
|
||||
|
||||
setupTabs()
|
||||
|
||||
val showNotification: Boolean = intent.getBooleanExtra(SHOW_NOTIFICATION_TAG, false)
|
||||
|
||||
|
@ -465,29 +456,90 @@ class MainActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupTabs(tab_array: List<() -> Fragment>){
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
private fun setupTabs() {
|
||||
val tabsCheckedDbEntry = with (db.userDao().getActiveUser()!!) {
|
||||
db.tabsDao().getTabsChecked(user_id, instance_uri)
|
||||
}
|
||||
val pageIds = listOf(R.id.page_1, R.id.page_2, R.id.page_3, R.id.page_4, R.id.page_5)
|
||||
|
||||
fun Tab.getFragment(): (() -> Fragment) {
|
||||
return when (this) {
|
||||
Tab.HOME_FEED -> { {
|
||||
PostFeedFragment<HomeStatusDatabaseEntity>()
|
||||
.apply {
|
||||
arguments = Bundle().apply { putBoolean("home", true) }
|
||||
}
|
||||
} }
|
||||
Tab.SEARCH_DISCOVER_FEED -> { { SearchDiscoverFragment() } }
|
||||
Tab.CREATE_FEED -> { { CameraFragment() } }
|
||||
Tab.NOTIFICATIONS_FEED -> { { NotificationsFragment() } }
|
||||
Tab.PUBLIC_FEED -> { {
|
||||
PostFeedFragment<PublicFeedStatusDatabaseEntity>()
|
||||
.apply {
|
||||
arguments = Bundle().apply { putBoolean("home", false) }
|
||||
}
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
val tabs = if (tabsCheckedDbEntry.isEmpty()) {
|
||||
// Load default menu
|
||||
loadDefaultMenuTabs(applicationContext, binding.root)
|
||||
} else {
|
||||
// Get current menu visibility and order from settings
|
||||
val tabsChecked = loadDbMenuTabs(applicationContext, tabsCheckedDbEntry).filter { it.second }.map { it.first }
|
||||
|
||||
val bottomNavigationMenu: Menu? = (binding.tabs as? NavigationBarView)?.menu?.apply {
|
||||
clear()
|
||||
}
|
||||
?: binding.navigation?.menu?.apply {
|
||||
removeGroup(R.id.tabsId)
|
||||
}
|
||||
|
||||
tabsChecked.zip(pageIds).forEach { (tabId, pageId) ->
|
||||
with(bottomNavigationMenu?.add(R.id.tabsId, pageId, 1, tabId.toLanguageString(baseContext))) {
|
||||
val tabIcon = tabId.getDrawable(applicationContext)
|
||||
if (tabIcon != null) {
|
||||
this?.icon = tabIcon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tabsChecked
|
||||
}
|
||||
|
||||
val tabArray: List<() -> Fragment> = tabs.map { it.getFragment() }
|
||||
binding.viewPager.reduceDragSensitivity()
|
||||
binding.viewPager.adapter = object : FragmentStateAdapter(this) {
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return tab_array[position]()
|
||||
return tabArray[position]()
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return tab_array.size
|
||||
return tabArray.size
|
||||
}
|
||||
}
|
||||
|
||||
val notificationId = tabs.zip(pageIds).find {
|
||||
it.first == Tab.NOTIFICATIONS_FEED
|
||||
}?.second
|
||||
|
||||
fun doAtPageId(pageId: Int): Int {
|
||||
if (notificationId != null && pageId == notificationId) {
|
||||
setNotificationBadge(false)
|
||||
}
|
||||
return pageId
|
||||
}
|
||||
|
||||
binding.viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
val selected = when(position){
|
||||
0 -> R.id.page_1
|
||||
1 -> R.id.page_2
|
||||
2 -> R.id.page_3
|
||||
3 -> {
|
||||
setNotificationBadge(false)
|
||||
R.id.page_4
|
||||
}
|
||||
4 -> R.id.page_5
|
||||
0 -> doAtPageId(R.id.page_1)
|
||||
1 -> doAtPageId(R.id.page_2)
|
||||
2 -> doAtPageId(R.id.page_3)
|
||||
3 -> doAtPageId(R.id.page_4)
|
||||
4 -> doAtPageId(R.id.page_5)
|
||||
else -> null
|
||||
}
|
||||
if (selected != null) {
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
package org.pixeldroid.app.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.checkbox.MaterialCheckBox
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
import org.pixeldroid.app.R
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.db.entities.TabsDatabaseEntity
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ArrangeTabsFragment: DialogFragment() {
|
||||
|
||||
@Inject
|
||||
lateinit var db: AppDatabase
|
||||
|
||||
private val model: ArrangeTabsViewModel by viewModels { ArrangeTabsViewModelFactory(requireContext(), db) }
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
|
||||
val inflater: LayoutInflater = requireActivity().layoutInflater
|
||||
val dialogView: View = inflater.inflate(R.layout.layout_tabs_arrange, null)
|
||||
|
||||
model.initTabsChecked(dialogView)
|
||||
|
||||
val listFeed: RecyclerView = dialogView.findViewById(R.id.tabs)
|
||||
val listAdapter = ListViewAdapter(model)
|
||||
listFeed.adapter = listAdapter
|
||||
listFeed.layoutManager = LinearLayoutManager(requireActivity())
|
||||
val callback = object: ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) {
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
source: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
listAdapter.onItemMove(source.bindingAdapterPosition, target.bindingAdapterPosition)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
// Do nothing, all items should remain in the list
|
||||
}
|
||||
}
|
||||
val itemTouchHelper = ItemTouchHelper(callback)
|
||||
itemTouchHelper.attachToRecyclerView(listFeed)
|
||||
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setIcon(R.drawable.outline_bottom_navigation)
|
||||
setTitle(R.string.arrange_tabs_summary)
|
||||
setView(dialogView)
|
||||
setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
// Save values into preferences
|
||||
val tabsChecked = listAdapter.model.uiState.value.tabsChecked.toList()
|
||||
val tabsDbEntity = tabsChecked.mapIndexed { index, (tab, checked) -> with (db.userDao().getActiveUser()!!) {
|
||||
TabsDatabaseEntity(index, user_id, instance_uri, tab.name, checked)
|
||||
} }
|
||||
lifecycleScope.launch {
|
||||
db.tabsDao().clearAndRefill(tabsDbEntity, model.uiState.value.userId, model.uiState.value.instanceUri)
|
||||
}
|
||||
}
|
||||
}.create()
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
||||
inner class ListViewAdapter(val model: ArrangeTabsViewModel):
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = FrameLayout.inflate(context, R.layout.layout_tab, null)
|
||||
|
||||
// Make sure the layout occupies full width
|
||||
view.layoutParams = FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
|
||||
return object: RecyclerView.ViewHolder(view) {}
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val textView: MaterialButton = holder.itemView.findViewById(R.id.textView)
|
||||
val checkBox: MaterialCheckBox = holder.itemView.findViewById(R.id.checkBox)
|
||||
val dragHandle: ImageView = holder.itemView.findViewById(R.id.dragHandle)
|
||||
|
||||
// Set content of each entry
|
||||
textView.text = model.uiState.value.tabsChecked[position].first.toLanguageString(requireContext())
|
||||
checkBox.isChecked = model.uiState.value.tabsChecked[position].second
|
||||
|
||||
// Also interact with checkbox when button is clicked
|
||||
textView.setOnClickListener {
|
||||
val isCheckedNew = !model.uiState.value.tabsChecked[position].second
|
||||
model.tabsCheckReplace(position, Pair(model.uiState.value.tabsChecked[position].first, isCheckedNew))
|
||||
checkBox.isChecked = isCheckedNew
|
||||
|
||||
// Disable OK button when no tab is selected or when strictly more than 5 tabs are selected
|
||||
val maxItemCount = BottomNavigationView(requireContext()).maxItemCount // = 5
|
||||
(requireDialog() as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)?.isEnabled =
|
||||
with (model.uiState.value.tabsChecked.count { (_, v) -> v }) { this in 1..maxItemCount}
|
||||
}
|
||||
|
||||
// Also highlight button when checkbox is clicked
|
||||
checkBox.setOnTouchListener { _, motionEvent ->
|
||||
textView.dispatchTouchEvent(motionEvent)
|
||||
}
|
||||
|
||||
// Do not highlight the button when the drag handle is touched
|
||||
dragHandle.setOnTouchListener { _, _ -> true }
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return model.uiState.value.tabsChecked.size
|
||||
}
|
||||
|
||||
fun onItemMove(from: Int, to: Int) {
|
||||
val previous = model.tabsCheckedRemove(from)
|
||||
model.tabsCheckedAdd(to, previous)
|
||||
notifyItemMoved(from, to)
|
||||
notifyItemChanged(to) // necessary to avoid checkBox issues
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package org.pixeldroid.app.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.pixeldroid.app.utils.Tab
|
||||
import org.pixeldroid.app.utils.db.AppDatabase
|
||||
import org.pixeldroid.app.utils.db.entities.TabsDatabaseEntity
|
||||
import org.pixeldroid.app.utils.loadDbMenuTabs
|
||||
import org.pixeldroid.app.utils.loadDefaultMenuTabs
|
||||
|
||||
|
||||
class ArrangeTabsViewModelFactory(
|
||||
private val context: Context, private val db: AppDatabase
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
if (modelClass.isAssignableFrom(ArrangeTabsViewModel::class.java)) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return ArrangeTabsViewModel(context, db) as T
|
||||
}
|
||||
throw IllegalArgumentException("Unknown ViewModel class")
|
||||
}
|
||||
}
|
||||
|
||||
class ArrangeTabsViewModel(
|
||||
private val fragmentContext: Context,
|
||||
private val db: AppDatabase
|
||||
): ViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow(ArrangeTabsUiState())
|
||||
val uiState: StateFlow<ArrangeTabsUiState> = _uiState
|
||||
|
||||
private var oldTabsChecked: MutableList<Pair<Tab, Boolean>> = mutableListOf()
|
||||
|
||||
init {
|
||||
initTabsDbEntities()
|
||||
}
|
||||
|
||||
private fun initTabsDbEntities() {
|
||||
val user = db.userDao().getActiveUser()!!
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
userId = user.user_id,
|
||||
instanceUri = user.instance_uri,
|
||||
)
|
||||
}
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
tabsDbEntities = db.tabsDao().getTabsChecked(_uiState.value.userId, _uiState.value.instanceUri)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun initTabsChecked(view: View) {
|
||||
if (oldTabsChecked.isEmpty()) {
|
||||
// Only load tabsChecked if the model has not been updated
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
tabsChecked = if (_uiState.value.tabsDbEntities.isEmpty()) {
|
||||
// Load default menu
|
||||
val list = loadDefaultMenuTabs(fragmentContext, view)
|
||||
list.zip(List(list.size){true}.toTypedArray()).toList()
|
||||
} else {
|
||||
// Get current menu visibility and order from settings
|
||||
loadDbMenuTabs(fragmentContext, _uiState.value.tabsDbEntities).toList()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun tabsCheckReplace(position: Int, pair: Pair<Tab, Boolean>) {
|
||||
oldTabsChecked = _uiState.value.tabsChecked.toMutableList()
|
||||
oldTabsChecked[position] = pair
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
tabsChecked = oldTabsChecked.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun tabsCheckedRemove(position: Int): Pair<Tab, Boolean> {
|
||||
oldTabsChecked = _uiState.value.tabsChecked.toMutableList()
|
||||
val removedPair = oldTabsChecked.removeAt(position)
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
tabsChecked = oldTabsChecked.toList()
|
||||
)
|
||||
}
|
||||
return removedPair
|
||||
}
|
||||
|
||||
fun tabsCheckedAdd(position: Int, pair: Pair<Tab, Boolean>) {
|
||||
oldTabsChecked = _uiState.value.tabsChecked.toMutableList()
|
||||
oldTabsChecked.add(position, pair)
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
tabsChecked = oldTabsChecked.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ArrangeTabsUiState(
|
||||
val userId: String = "",
|
||||
val instanceUri: String = "",
|
||||
val tabsDbEntities: List<TabsDatabaseEntity> = listOf(),
|
||||
val tabsChecked: List<Pair<Tab, Boolean>> = listOf()
|
||||
)
|
|
@ -0,0 +1,56 @@
|
|||
package org.pixeldroid.app.settings
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.res.XmlResourceParser
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.pixeldroid.app.R
|
||||
|
||||
class LanguageSettingFragment : DialogFragment() {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val list: MutableList<String> = mutableListOf()
|
||||
// IDE doesn't find it, but compiling works apparently?
|
||||
resources.getXml(R.xml._generated_res_locale_config).use {
|
||||
var eventType = it.eventType
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
when (eventType) {
|
||||
XmlResourceParser.START_TAG -> {
|
||||
if (it.name == "locale") {
|
||||
list.add(it.getAttributeValue(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
eventType = it.next()
|
||||
}
|
||||
}
|
||||
val locales = AppCompatDelegate.getApplicationLocales()
|
||||
val checkedItem: Int =
|
||||
if(locales.isEmpty) 0
|
||||
else {
|
||||
// For some reason we get a bit inconsistent language tags. This normalises it for
|
||||
// the currently used languages, but it might break in the future if we add some
|
||||
val index = list.indexOf(locales.get(0)?.toLanguageTag()?.lowercase()?.replace('_', '-'))
|
||||
// If found, we want to compensate for the first in the list being the default
|
||||
if(index == -1) -1
|
||||
else index + 1
|
||||
}
|
||||
|
||||
return MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setIcon(R.drawable.translate_black_24dp)
|
||||
setTitle(R.string.language)
|
||||
setSingleChoiceItems((mutableListOf(getString(R.string.default_system)) + list.map {
|
||||
val appLocale = LocaleListCompat.forLanguageTags(it)
|
||||
appLocale.get(0)!!.getDisplayName(appLocale.get(0)!!)
|
||||
}).toTypedArray(), checkedItem) { dialog, which ->
|
||||
val languageTag = if(which in 1..list.size) list[which - 1] else null
|
||||
dialog.dismiss()
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(languageTag))
|
||||
}
|
||||
setNegativeButton(android.R.string.ok) { _, _ -> }
|
||||
}.create()
|
||||
}
|
||||
}
|
|
@ -1,28 +1,27 @@
|
|||
package org.pixeldroid.app.settings
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.XmlResourceParser
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.activity.addCallback
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.pixeldroid.app.main.MainActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.pixeldroid.app.R
|
||||
import org.pixeldroid.app.databinding.SettingsBinding
|
||||
import org.pixeldroid.common.ThemedActivity
|
||||
import org.pixeldroid.app.main.MainActivity
|
||||
import org.pixeldroid.app.utils.setThemeFromPreferences
|
||||
import org.pixeldroid.common.ThemedActivity
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsActivity : ThemedActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private var restartMainOnExit = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -103,6 +102,8 @@ class SettingsActivity : ThemedActivity(), SharedPreferences.OnSharedPreferenceC
|
|||
dialogFragment = ColorPreferenceDialog((preference as ColorPreference?)!!)
|
||||
} else if(preference.key == "language"){
|
||||
dialogFragment = LanguageSettingFragment()
|
||||
} else if (preference.key == "arrange_tabs") {
|
||||
dialogFragment = ArrangeTabsFragment()
|
||||
}
|
||||
if (dialogFragment != null) {
|
||||
dialogFragment.setTargetFragment(this, 0)
|
||||
|
@ -129,49 +130,4 @@ class SettingsActivity : ThemedActivity(), SharedPreferences.OnSharedPreferenceC
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
class LanguageSettingFragment : DialogFragment() {
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val list: MutableList<String> = mutableListOf()
|
||||
// IDE doesn't find it, but compiling works apparently?
|
||||
resources.getXml(R.xml._generated_res_locale_config).use {
|
||||
var eventType = it.eventType
|
||||
while (eventType != XmlResourceParser.END_DOCUMENT) {
|
||||
when (eventType) {
|
||||
XmlResourceParser.START_TAG -> {
|
||||
if (it.name == "locale") {
|
||||
list.add(it.getAttributeValue(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
eventType = it.next()
|
||||
}
|
||||
}
|
||||
val locales = AppCompatDelegate.getApplicationLocales()
|
||||
val checkedItem: Int =
|
||||
if(locales.isEmpty) 0
|
||||
else {
|
||||
// For some reason we get a bit inconsistent language tags. This normalises it for
|
||||
// the currently used languages, but it might break in the future if we add some
|
||||
val index = list.indexOf(locales.get(0)?.toLanguageTag()?.lowercase()?.replace('_', '-'))
|
||||
// If found, we want to compensate for the first in the list being the default
|
||||
if(index == -1) -1
|
||||
else index + 1
|
||||
}
|
||||
|
||||
return MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setIcon(R.drawable.translate_black_24dp)
|
||||
setTitle(R.string.language)
|
||||
setSingleChoiceItems((mutableListOf(getString(R.string.default_system)) + list.map {
|
||||
val appLocale = LocaleListCompat.forLanguageTags(it)
|
||||
appLocale.get(0)!!.getDisplayName(appLocale.get(0)!!)
|
||||
}).toTypedArray(), checkedItem) { dialog, which ->
|
||||
val languageTag = if(which in 1..list.size) list[which - 1] else null
|
||||
dialog.dismiss()
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(languageTag))
|
||||
}
|
||||
setNegativeButton(android.R.string.ok) { _, _ -> }
|
||||
}.create()
|
||||
}
|
||||
}
|
|
@ -7,15 +7,19 @@ import android.content.Intent
|
|||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
|
@ -29,6 +33,7 @@ import com.google.gson.JsonPrimitive
|
|||
import com.google.gson.JsonSerializer
|
||||
import okhttp3.HttpUrl
|
||||
import org.pixeldroid.app.R
|
||||
import org.pixeldroid.app.utils.db.entities.TabsDatabaseEntity
|
||||
import java.time.Instant
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Locale
|
||||
|
@ -193,3 +198,66 @@ fun <T> Fragment.bindingLifecycleAware(): ReadWriteProperty<Fragment, T> =
|
|||
this@bindingLifecycleAware.viewLifecycleOwner.lifecycle.addObserver(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadDefaultMenuTabs(context: Context, anchor: View): List<Tab> {
|
||||
return with(PopupMenu(context, anchor)) {
|
||||
val menu = this.menu
|
||||
menuInflater.inflate(R.menu.navigation_main, menu)
|
||||
menu.removeGroup(R.id.bottomNavigationGroup)
|
||||
(0 until menu.size()).map { Tab.fromLanguageString(context, menu.getItem(it).title.toString()) }
|
||||
}
|
||||
}
|
||||
|
||||
fun loadDbMenuTabs(ctx: Context, tabsDbEntry: List<TabsDatabaseEntity>): List<Pair<Tab, Boolean>> {
|
||||
return tabsDbEntry.map {
|
||||
Pair(Tab.fromName(it.tab), it.checked)
|
||||
}
|
||||
}
|
||||
|
||||
enum class Tab {
|
||||
HOME_FEED, SEARCH_DISCOVER_FEED, CREATE_FEED, NOTIFICATIONS_FEED, PUBLIC_FEED;
|
||||
|
||||
fun toLanguageString(ctx: Context): String {
|
||||
return ctx.getString(
|
||||
when (this) {
|
||||
HOME_FEED -> R.string.home_feed
|
||||
SEARCH_DISCOVER_FEED -> R.string.search_discover_feed
|
||||
CREATE_FEED -> R.string.create_feed
|
||||
NOTIFICATIONS_FEED -> R.string.notifications_feed
|
||||
PUBLIC_FEED -> R.string.public_feed
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun toName(): String {
|
||||
return this.name
|
||||
}
|
||||
|
||||
fun getDrawable(ctx: Context): Drawable? {
|
||||
val resId = when (this) {
|
||||
HOME_FEED -> R.drawable.selector_home_feed
|
||||
SEARCH_DISCOVER_FEED -> R.drawable.ic_search_white_24dp
|
||||
CREATE_FEED -> R.drawable.selector_camera
|
||||
NOTIFICATIONS_FEED -> R.drawable.selector_notifications
|
||||
PUBLIC_FEED -> R.drawable.ic_filter_black_24dp
|
||||
}
|
||||
return AppCompatResources.getDrawable(ctx, resId)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromLanguageString(ctx: Context, name: String): Tab {
|
||||
return when (name) {
|
||||
ctx.getString(R.string.home_feed) -> HOME_FEED
|
||||
ctx.getString(R.string.search_discover_feed) -> SEARCH_DISCOVER_FEED
|
||||
ctx.getString(R.string.create_feed) -> CREATE_FEED
|
||||
ctx.getString(R.string.notifications_feed) -> NOTIFICATIONS_FEED
|
||||
ctx.getString(R.string.public_feed) -> PUBLIC_FEED
|
||||
else -> HOME_FEED
|
||||
}
|
||||
}
|
||||
|
||||
fun fromName(name: String): Tab {
|
||||
return entries.filter { it.name == name }.getOrElse(0) { HOME_FEED }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package org.pixeldroid.app.utils.db
|
||||
|
||||
import androidx.room.AutoMigration
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
|
@ -14,15 +15,20 @@ import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity
|
|||
import org.pixeldroid.app.utils.db.entities.PublicFeedStatusDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import org.pixeldroid.app.utils.api.objects.Notification
|
||||
import org.pixeldroid.app.utils.db.entities.TabsDatabaseEntity
|
||||
|
||||
@Database(entities = [
|
||||
InstanceDatabaseEntity::class,
|
||||
UserDatabaseEntity::class,
|
||||
HomeStatusDatabaseEntity::class,
|
||||
PublicFeedStatusDatabaseEntity::class,
|
||||
Notification::class
|
||||
Notification::class,
|
||||
TabsDatabaseEntity::class
|
||||
],
|
||||
version = 7,
|
||||
autoMigrations = [
|
||||
AutoMigration(from = 6, to = 7)
|
||||
],
|
||||
version = 6
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
@ -31,6 +37,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||
abstract fun homePostDao(): HomePostDao
|
||||
abstract fun publicPostDao(): PublicPostDao
|
||||
abstract fun notificationDao(): NotificationDao
|
||||
abstract fun tabsDao(): TabsDao
|
||||
}
|
||||
|
||||
val MIGRATION_3_4 = object : Migration(3, 4) {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package org.pixeldroid.app.utils.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import org.pixeldroid.app.utils.db.entities.TabsDatabaseEntity
|
||||
|
||||
@Dao
|
||||
interface TabsDao {
|
||||
@Query("SELECT * FROM tabsChecked WHERE `index`=:index AND `user_id`=:userId AND `instance_uri`=:instanceUri")
|
||||
fun getTabChecked(index: Int, userId: String, instanceUri: String): TabsDatabaseEntity
|
||||
|
||||
@Query("SELECT * FROM tabsChecked WHERE `user_id`=:userId AND `instance_uri`=:instanceUri")
|
||||
fun getTabsChecked(userId: String, instanceUri: String): List<TabsDatabaseEntity>
|
||||
|
||||
@Query("DELETE FROM tabsChecked WHERE `index`=:index AND `user_id`=:userId AND `instance_uri`=:instanceUri")
|
||||
fun deleteTabChecked(index: Int, userId: String, instanceUri: String)
|
||||
|
||||
@Query("DELETE FROM tabsChecked WHERE `user_id`=:userId AND `instance_uri`=:instanceUri")
|
||||
fun deleteTabsChecked(userId: String, instanceUri: String)
|
||||
|
||||
/**
|
||||
* Insert a tab, if it already exists return -1
|
||||
*/
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insertTabChecked(tabChecked: TabsDatabaseEntity): Long
|
||||
|
||||
@Update
|
||||
suspend fun updateTabChecked(tabChecked: TabsDatabaseEntity)
|
||||
|
||||
@Transaction
|
||||
suspend fun insertOrUpdate(tabChecked: TabsDatabaseEntity) {
|
||||
if (insertTabChecked(tabChecked) == -1L) {
|
||||
updateTabChecked(tabChecked)
|
||||
}
|
||||
}
|
||||
|
||||
@Transaction
|
||||
suspend fun clearAndRefill(tabsChecked: List<TabsDatabaseEntity>, userId: String, instanceUri: String) {
|
||||
deleteTabsChecked(userId, instanceUri)
|
||||
tabsChecked.forEach { insertTabChecked(it) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.pixeldroid.app.utils.db.entities
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
|
||||
@Entity(
|
||||
tableName = "tabsChecked",
|
||||
primaryKeys = ["index", "user_id", "instance_uri"],
|
||||
foreignKeys = [ForeignKey(
|
||||
entity = UserDatabaseEntity::class,
|
||||
parentColumns = arrayOf("user_id", "instance_uri"),
|
||||
childColumns = arrayOf("user_id", "instance_uri"),
|
||||
onUpdate = ForeignKey.CASCADE,
|
||||
onDelete = ForeignKey.CASCADE
|
||||
)],
|
||||
indices = [Index(value = ["user_id", "instance_uri"])]
|
||||
)
|
||||
data class TabsDatabaseEntity(
|
||||
var index: Int,
|
||||
var user_id: String,
|
||||
var instance_uri: String,
|
||||
var tab: String,
|
||||
var checked: Boolean = true,
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="960" android:viewportWidth="960"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnBackground" android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,600L760,600L760,200Q760,200 760,200Q760,200 760,200L200,200Q200,200 200,200Q200,200 200,200L200,600ZM200,680L200,760Q200,760 200,760Q200,760 200,760L760,760Q760,760 760,760Q760,760 760,760L760,680L200,680ZM200,680L200,680L200,760Q200,760 200,760Q200,760 200,760L200,760Q200,760 200,760Q200,760 200,760L200,680Z"/>
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="960" android:viewportWidth="960"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnBackground" android:pathData="M346,820L100,574Q90,564 85,552Q80,540 80,527Q80,514 85,502Q90,490 100,480L330,251L255,176Q242,163 241.5,145Q241,127 254,113Q267,99 286,99Q305,99 319,113L686,480Q696,490 700.5,502Q705,514 705,527Q705,540 700.5,552Q696,564 686,574L440,820Q430,830 418,835Q406,840 393,840Q380,840 368,835Q356,830 346,820ZM393,314L179,528Q179,528 179,528Q179,528 179,528L607,528Q607,528 607,528Q607,528 607,528L393,314ZM792,840Q756,840 731,814.5Q706,789 706,752Q706,725 719.5,701Q733,677 750,654L769,630Q778,619 792.5,618.5Q807,618 816,629L836,654Q852,677 866,701Q880,725 880,752Q880,789 854,814.5Q828,840 792,840Z"/>
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="960" android:viewportWidth="960"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/colorOnBackground" android:pathData="M200,600Q183,600 171.5,588.5Q160,577 160,560Q160,543 171.5,531.5Q183,520 200,520L760,520Q777,520 788.5,531.5Q800,543 800,560Q800,577 788.5,588.5Q777,600 760,600L200,600ZM200,440Q183,440 171.5,428.5Q160,417 160,400Q160,383 171.5,371.5Q183,360 200,360L760,360Q777,360 788.5,371.5Q800,383 800,400Q800,417 788.5,428.5Q777,440 760,440L200,440Z"/>
|
||||
</vector>
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cornerRadius="0dp"
|
||||
android:gravity="start|center_vertical"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
android:textAllCaps="false"
|
||||
android:textAppearance="?attr/textAppearanceBody1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingStart="75dp"
|
||||
android:paddingEnd="75dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5" />
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
android:id="@+id/checkBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="40dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/textView"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/textView"
|
||||
app:layout_constraintVertical_bias="0.5"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dragHandle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:src="@drawable/rounded_drag_handle"
|
||||
android:paddingEnd="15dp"
|
||||
android:paddingStart="15dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/textView"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/textView"
|
||||
app:layout_constraintVertical_bias="0.5"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.widget.Space
|
||||
android:id="@+id/titleDividerNoCustom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/m3_alert_dialog_title_bottom_margin"
|
||||
/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
|
@ -27,7 +27,9 @@
|
|||
android:icon="@drawable/ic_filter_black_24dp"
|
||||
android:title="@string/public_feed"/>
|
||||
</group>
|
||||
|
||||
<group
|
||||
android:id="@+id/bottomNavigationGroup"
|
||||
android:orderInCategory="3">
|
||||
<item
|
||||
android:id="@+id/my_profile"
|
||||
android:enabled="true"
|
||||
|
@ -43,4 +45,6 @@
|
|||
android:enabled="true"
|
||||
android:icon="@drawable/logout"
|
||||
android:title="@string/logout"/>
|
||||
</group>
|
||||
|
||||
</menu>
|
|
@ -348,4 +348,7 @@ For more info about Pixelfed, you can check here: https://pixelfed.org"</string>
|
|||
<string name="continue_post_creation">Continue</string>
|
||||
<string name="extraneous_pictures_stories">Pictures after the first were removed but can be restored by switching back to creating a Post</string>
|
||||
<string name="story_duration">Story Duration</string>
|
||||
<string name="arrange_tabs_summary">Arrange tabs</string>
|
||||
<string name="arrange_tabs_description">Change visibility and order of tabs</string>
|
||||
<string name="content_header">Content</string>
|
||||
</resources>
|
||||
|
|
|
@ -17,18 +17,31 @@
|
|||
android:title="@string/accentColorTitle"
|
||||
android:key="themeColor"
|
||||
android:defaultValue="0"
|
||||
android:summary="@string/accentColorSummary" />
|
||||
</PreferenceCategory>
|
||||
android:summary="@string/accentColorSummary"
|
||||
app:icon="@drawable/rounded_colors"/>
|
||||
|
||||
<ListPreference
|
||||
app:key="language"
|
||||
app:title="@string/language"
|
||||
app:icon="@drawable/translate_black_24dp" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="@string/content_header">
|
||||
<ListPreference
|
||||
android:key="arrange_tabs"
|
||||
android:title="@string/arrange_tabs_summary"
|
||||
android:summary="@string/arrange_tabs_description"
|
||||
android:icon="@drawable/outline_bottom_navigation" />
|
||||
|
||||
<CheckBoxPreference app:key="always_show_nsfw" app:title="@string/always_show_nsfw"
|
||||
app:icon="@drawable/eye_black_24dp" android:defaultValue="false"
|
||||
android:summary="@string/summary_always_show_nsfw"/>
|
||||
|
||||
<EditTextPreference android:title="@string/description_template"
|
||||
android:key="prefill_description"
|
||||
android:summary="@string/description_template_summary"
|
||||
app:icon="@drawable/note" />
|
||||
|
||||
<Preference android:title="@string/notifications_settings"
|
||||
android:key="notification"
|
||||
android:summary="@string/notifications_settings_summary"
|
||||
|
@ -38,12 +51,9 @@
|
|||
android:value="@string/application_id" />
|
||||
</intent>
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
|
||||
<EditTextPreference android:title="@string/description_template"
|
||||
android:key="prefill_description"
|
||||
android:summary="@string/description_template_summary"
|
||||
app:icon="@drawable/note" />
|
||||
|
||||
<PreferenceCategory app:title="@string/about">
|
||||
<Preference android:title="@string/about"
|
||||
android:key="about"
|
||||
android:summary="@string/about_pixeldroid"
|
||||
|
@ -65,6 +75,6 @@
|
|||
<extra android:name="translatePlatformUrl" android:value="https://weblate.pixeldroid.org" />
|
||||
<extra android:name="contributeForgeUrl" android:value="https://gitlab.shinice.net/pixeldroid/PixelDroid" />
|
||||
</intent>
|
||||
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
|
Loading…
Reference in New Issue