diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/Constants.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/Constants.kt index b195dae11..dc52db778 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/Constants.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/Constants.kt @@ -2,8 +2,6 @@ package dev.ragnarok.fenrir import android.content.res.Resources import android.os.Build -import dev.ragnarok.fenrir.db.column.GroupColumns -import dev.ragnarok.fenrir.db.column.UserColumns import dev.ragnarok.fenrir.settings.ISettings import dev.ragnarok.fenrir.settings.Settings import dev.ragnarok.fenrir.util.Utils @@ -11,7 +9,7 @@ import java.util.* object Constants { const val API_VERSION = "5.131" - const val DATABASE_FENRIR_VERSION = 22 + const val DATABASE_FENRIR_VERSION = 25 const val DATABASE_TEMPORARY_VERSION = 5 const val EXPORT_SETTINGS_FORMAT = 1 const val forceDeveloperMode = BuildConfig.FORCE_DEVELOPER_MODE @@ -22,12 +20,11 @@ object Constants { val AUTH_VERSION = if (DEFAULT_ACCOUNT_TYPE == AccountType.KATE) API_VERSION else "5.122" const val FILE_PROVIDER_AUTHORITY: String = BuildConfig.APPLICATION_ID + ".file_provider" const val VK_ANDROID_APP_VERSION_NAME = "8.11" - const val VK_ANDROID_APP_VERSION_CODE = "15026" + const val VK_ANDROID_APP_VERSION_CODE = "15060" const val KATE_APP_VERSION_NAME = "96 lite" const val KATE_APP_VERSION_CODE = "529" const val API_ID: Int = BuildConfig.VK_API_APP_ID const val SECRET: String = BuildConfig.VK_CLIENT_SECRET - const val MAIN_OWNER_FIELDS = UserColumns.API_FIELDS + "," + GroupColumns.API_FIELDS const val PHOTOS_PATH = "DCIM/Fenrir" const val AUDIO_PLAYER_SERVICE_IDLE = 300000 const val PIN_DIGITS_COUNT = 4 diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/CaptchaNeedException.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/CaptchaNeedException.kt index f0a789cf7..85c93554a 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/CaptchaNeedException.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/CaptchaNeedException.kt @@ -1,3 +1,3 @@ package dev.ragnarok.fenrir.api -class CaptchaNeedException(val sid: String?, val img: String?) : Exception() \ No newline at end of file +class CaptchaNeedException(val sid: String?, val img: String?) : Exception("Captcha required!") \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/Fields.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/Fields.kt new file mode 100644 index 000000000..088d78631 --- /dev/null +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/Fields.kt @@ -0,0 +1,273 @@ +package dev.ragnarok.fenrir.api + +import dev.ragnarok.fenrir.util.Utils + +object Fields { + object USER_FIELDS { + const val ABOUT = "about" + const val ACTIVITIES = "activities" + const val ACTIVITY = "activity" + const val BDATE = "bdate" + const val BLACKLISTED = "blacklisted" + const val BLACKLISTED_BY_ME = "blacklisted_by_me" + const val BOOKS = "books" + const val CAN_ACCESS_CLOSED = "can_access_closed" + const val CAN_POST = "can_post" + const val CAN_SEE_ALL_POSTS = "can_see_all_posts" + const val CAN_SEND_FRIEND_REQUEST = "can_send_friend_request" + const val CAN_WRITE_PRIVATE_MESSAGE = "can_write_private_message" + const val CAREER = "career" + const val CITY = "city" + const val COMMON_COUNT = "common_count" + const val CONNECTIONS = "connections" + const val CONTACTS = "contacts" + const val COUNTERS = "counters" + const val COUNTRY = "country" + const val COVER = "cover" + const val DOMAIN = "domain" + const val EDUCATION = "education" + const val FIRST_NAME = "first_name" + const val FRIEND_STATUS = "friend_status" + const val GAMES = "games" + const val HAS_MOBILE = "has_mobile" + const val HAS_UNSEEN_STORIES = "has_unseen_stories" + const val HOME_TOWN = "home_town" + const val INTERESTS = "interests" + const val IS_CLOSED = "is_closed" + const val IS_FAVORITE = "is_favorite" + const val IS_FRIEND = "is_friend" + const val IS_SUBSCRIBED = "is_subscribed" + const val LAST_NAME = "last_name" + const val LAST_SEEN = "last_seen" + const val MAIDEN_NAME = "maiden_name" + const val MILITARY = "military" + const val MOVIES = "movies" + const val MUSIC = "music" + const val OCCUPATION = "occupation" + const val ONLINE = "online" + const val ONLINE_APP = "online_app" + const val ONLINE_MOBILE = "online_mobile" + const val PERSONAL = "personal" + const val PHOTO_100 = "photo_100" + const val PHOTO_200 = "photo_200" + const val PHOTO_50 = "photo_50" + const val PHOTO_ID = "photo_id" + const val PHOTO_MAX_ORIG = "photo_max_orig" + const val PLATFORM = "platform" + const val QUOTES = "quotes" + const val RELATION = "relation" + const val RELATIVES = "relatives" + const val SCHOOLS = "schools" + const val SCREEN_NAME = "screen_name" + const val SEX = "sex" + const val SITE = "site" + const val STATUS = "status" + const val TIMEZONE = "timezone" + const val TV = "tv" + const val UNIVERSITIES = "universities" + const val VERIFIED = "verified" + const val WALL_DEFAULT = "wall_default" + } + + object GROUP_FIELDS { + const val ACTIVITY = "activity" + const val ADMIN_LEVEL = "admin_level" + const val BAN_INFO = "ban_info" + const val BLACKLISTED = "blacklisted" + const val CAN_CREATE_TOPIC = "can_create_topic" + const val CAN_MESSAGE = "can_message" + const val CAN_POST = "can_post" + const val CAN_SEE_ALL_POSTS = "can_see_all_posts" + const val CAN_UPLOAD_DOC = "can_upload_doc" + const val CAN_UPLOAD_VIDEO = "can_upload_video" + const val CHATS_STATUS = "chats_status" + const val CITY = "city" + const val CONTACTS = "contacts" + const val COUNTERS = "counters" + const val COUNTRY = "country" + const val COVER = "cover" + const val DESCRIPTION = "description" + const val FINISH_DATE = "finish_date" + const val FIXED_POST = "fixed_post" + const val HAS_UNSEEN_STORIES = "has_unseen_stories" + const val IS_ADMIN = "is_admin" + const val IS_CLOSED = "is_closed" + const val IS_FAVORITE = "is_favorite" + const val IS_MEMBER = "is_member" + const val IS_SUBSCRIBED = "is_subscribed" + const val LINKS = "links" + const val MAIN_ALBUM_ID = "main_album_id" + const val MEMBERS_COUNT = "members_count" + const val MEMBER_STATUS = "member_status" + const val MENU = "menu" + const val NAME = "name" + const val PHOTO_100 = "photo_100" + const val PHOTO_200 = "photo_200" + const val PHOTO_50 = "photo_50" + const val SCREEN_NAME = "screen_name" + const val SITE = "site" + const val START_DATE = "start_date" + const val STATUS = "status" + const val TYPE = "type" + const val VERIFIED = "verified" + } + + private val LIST_FIELDS_BASE_USER = + listOf( + USER_FIELDS.BDATE, + USER_FIELDS.BLACKLISTED, + USER_FIELDS.BLACKLISTED_BY_ME, + USER_FIELDS.CAN_ACCESS_CLOSED, + USER_FIELDS.CAN_POST, + USER_FIELDS.CAN_SEE_ALL_POSTS, + USER_FIELDS.CAN_SEND_FRIEND_REQUEST, + USER_FIELDS.CAN_WRITE_PRIVATE_MESSAGE, + USER_FIELDS.DOMAIN, + USER_FIELDS.FIRST_NAME, + USER_FIELDS.FRIEND_STATUS, + USER_FIELDS.HAS_UNSEEN_STORIES, + USER_FIELDS.IS_CLOSED, + USER_FIELDS.IS_FAVORITE, + USER_FIELDS.IS_FRIEND, + USER_FIELDS.IS_SUBSCRIBED, + USER_FIELDS.LAST_NAME, + USER_FIELDS.LAST_SEEN, + USER_FIELDS.MAIDEN_NAME, + USER_FIELDS.ONLINE, + USER_FIELDS.ONLINE_APP, + USER_FIELDS.ONLINE_MOBILE, + USER_FIELDS.PHOTO_100, + USER_FIELDS.PHOTO_200, + USER_FIELDS.PHOTO_50, + USER_FIELDS.PHOTO_MAX_ORIG, + USER_FIELDS.PLATFORM, + USER_FIELDS.SCREEN_NAME, + USER_FIELDS.SEX, + USER_FIELDS.STATUS, + USER_FIELDS.VERIFIED + ) + + private val LIST_FIELDS_EXT_USER = listOf( + USER_FIELDS.ABOUT, + USER_FIELDS.ACTIVITIES, + USER_FIELDS.BOOKS, + USER_FIELDS.CAREER, + USER_FIELDS.CITY, + USER_FIELDS.COMMON_COUNT, + USER_FIELDS.CONNECTIONS, + USER_FIELDS.CONTACTS, + USER_FIELDS.COUNTERS, + USER_FIELDS.COUNTRY, + USER_FIELDS.COVER, + USER_FIELDS.EDUCATION, + USER_FIELDS.GAMES, + USER_FIELDS.HAS_MOBILE, + USER_FIELDS.INTERESTS, + USER_FIELDS.MILITARY, + USER_FIELDS.MOVIES, + USER_FIELDS.MUSIC, + USER_FIELDS.OCCUPATION, + USER_FIELDS.PERSONAL, + USER_FIELDS.PHOTO_ID, + USER_FIELDS.QUOTES, + USER_FIELDS.RELATION, + USER_FIELDS.RELATIVES, + USER_FIELDS.SCHOOLS, + USER_FIELDS.SITE, + USER_FIELDS.TIMEZONE, + USER_FIELDS.TV, + USER_FIELDS.UNIVERSITIES + ) + + private val LIST_FIELDS_BASE_GROUP = + listOf( + GROUP_FIELDS.ADMIN_LEVEL, + GROUP_FIELDS.BAN_INFO, + GROUP_FIELDS.HAS_UNSEEN_STORIES, + GROUP_FIELDS.IS_ADMIN, + GROUP_FIELDS.IS_CLOSED, + GROUP_FIELDS.IS_MEMBER, + GROUP_FIELDS.MEMBERS_COUNT, + GROUP_FIELDS.MEMBER_STATUS, + GROUP_FIELDS.MENU, + GROUP_FIELDS.NAME, + GROUP_FIELDS.PHOTO_100, + GROUP_FIELDS.PHOTO_200, + GROUP_FIELDS.PHOTO_50, + GROUP_FIELDS.SCREEN_NAME, + GROUP_FIELDS.TYPE, + GROUP_FIELDS.VERIFIED + ) + + private val LIST_FIELDS_EXT_GROUP = listOf( + GROUP_FIELDS.ACTIVITY, + GROUP_FIELDS.BLACKLISTED, + GROUP_FIELDS.CAN_CREATE_TOPIC, + GROUP_FIELDS.CAN_MESSAGE, + GROUP_FIELDS.CAN_POST, + GROUP_FIELDS.CAN_SEE_ALL_POSTS, + GROUP_FIELDS.CAN_UPLOAD_DOC, + GROUP_FIELDS.CAN_UPLOAD_VIDEO, + GROUP_FIELDS.CHATS_STATUS, + GROUP_FIELDS.CITY, + GROUP_FIELDS.CONTACTS, + GROUP_FIELDS.COUNTERS, + GROUP_FIELDS.COUNTRY, + GROUP_FIELDS.COVER, + GROUP_FIELDS.DESCRIPTION, + GROUP_FIELDS.FINISH_DATE, + GROUP_FIELDS.FIXED_POST, + GROUP_FIELDS.IS_FAVORITE, + GROUP_FIELDS.IS_SUBSCRIBED, + GROUP_FIELDS.LINKS, + GROUP_FIELDS.MAIN_ALBUM_ID, + GROUP_FIELDS.SITE, + GROUP_FIELDS.START_DATE, + GROUP_FIELDS.STATUS + ) + + private fun buildFields(vararg elements: List): String { + var counts = 0 + for (i in elements) { + counts += i.size + } + val list = ArrayList(counts) + for (i in elements) { + for (s in i) { + if (!list.contains(s)) { + list.add(s) + } + } + } + return Utils.join(",", list) + } + + val FIELDS_BASE_USER: String by lazy { + buildFields(LIST_FIELDS_BASE_USER) + } + + val FIELDS_BASE_GROUP: String by lazy { + buildFields(LIST_FIELDS_BASE_GROUP) + } + + val FIELDS_BASE_OWNER: String by lazy { + buildFields(LIST_FIELDS_BASE_USER, LIST_FIELDS_BASE_GROUP) + } + + val FIELDS_FULL_USER: String by lazy { + buildFields(LIST_FIELDS_BASE_USER, LIST_FIELDS_EXT_USER) + } + + val FIELDS_FULL_GROUP: String by lazy { + buildFields(LIST_FIELDS_BASE_GROUP, LIST_FIELDS_EXT_GROUP) + } + + val FIELDS_FULL_OWNER: String by lazy { + buildFields( + LIST_FIELDS_BASE_USER, + LIST_FIELDS_EXT_USER, + LIST_FIELDS_BASE_GROUP, + LIST_FIELDS_EXT_GROUP + ) + } +} \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/NeedValidationException.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/NeedValidationException.kt index 9261bc6f7..633246bbd 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/NeedValidationException.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/NeedValidationException.kt @@ -3,5 +3,6 @@ package dev.ragnarok.fenrir.api class NeedValidationException( val validationType: String?, val validationURL: String?, - val sid: String? -) : Exception() \ No newline at end of file + val sid: String?, + val description: String?, +) : Exception("Need Validation $description") \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/CommunityDtoAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/CommunityDtoAdapter.kt index c463f9f51..95f971a5d 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/CommunityDtoAdapter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/CommunityDtoAdapter.kt @@ -1,5 +1,6 @@ package dev.ragnarok.fenrir.api.adapters +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.model.* import dev.ragnarok.fenrir.api.util.VKStringUtils import dev.ragnarok.fenrir.kJson @@ -18,14 +19,14 @@ class CommunityDtoAdapter : AbsAdapter("VKApiCommunity") { val root = json.asJsonObject val dto = VKApiCommunity() dto.id = optInt(root, "id") - dto.name = optString(root, "name") + dto.name = optString(root, Fields.GROUP_FIELDS.NAME) dto.screen_name = optString( root, - "screen_name", + Fields.GROUP_FIELDS.SCREEN_NAME, String.format(Locale.getDefault(), "club%d", abs(dto.id)) ) - if (hasObject(root, "menu")) { - val pMenu = root.getAsJsonObject("menu") + if (hasObject(root, Fields.GROUP_FIELDS.MENU)) { + val pMenu = root.getAsJsonObject(Fields.GROUP_FIELDS.MENU) if (hasArray(pMenu, "items")) { dto.menu = ArrayList() for (i in pMenu.getAsJsonArray("items").orEmpty()) { @@ -57,15 +58,15 @@ class CommunityDtoAdapter : AbsAdapter("VKApiCommunity") { } } } - dto.is_closed = optInt(root, "is_closed") - dto.is_admin = optBoolean(root, "is_admin") - dto.admin_level = optInt(root, "admin_level") - dto.is_member = optBoolean(root, "is_member") - dto.member_status = optInt(root, "member_status") - dto.photo_50 = optString(root, "photo_50", VKApiCommunity.PHOTO_50) - dto.photo_100 = optString(root, "photo_100", VKApiCommunity.PHOTO_100) - dto.photo_200 = optString(root, "photo_200", null) - when (optString(root, "type", "group")) { + dto.is_closed = optInt(root, Fields.GROUP_FIELDS.IS_CLOSED) + dto.is_admin = optBoolean(root, Fields.GROUP_FIELDS.IS_ADMIN) + dto.admin_level = optInt(root, Fields.GROUP_FIELDS.ADMIN_LEVEL) + dto.is_member = optBoolean(root, Fields.GROUP_FIELDS.IS_MEMBER) + dto.member_status = optInt(root, Fields.GROUP_FIELDS.MEMBER_STATUS) + dto.photo_50 = optString(root, Fields.GROUP_FIELDS.PHOTO_50, VKApiCommunity.PHOTO_50) + dto.photo_100 = optString(root, Fields.GROUP_FIELDS.PHOTO_100, VKApiCommunity.PHOTO_100) + dto.photo_200 = optString(root, Fields.GROUP_FIELDS.PHOTO_200, null) + when (optString(root, Fields.GROUP_FIELDS.TYPE, "group")) { VKApiCommunity.TYPE_GROUP -> { dto.type = VKApiCommunity.Type.GROUP } @@ -76,75 +77,75 @@ class CommunityDtoAdapter : AbsAdapter("VKApiCommunity") { dto.type = VKApiCommunity.Type.EVENT } } - if (hasObject(root, VKApiCommunity.CITY)) { - dto.city = root[VKApiCommunity.CITY]?.let { + if (hasObject(root, Fields.GROUP_FIELDS.CITY)) { + dto.city = root[Fields.GROUP_FIELDS.CITY]?.let { kJson.decodeFromJsonElement(VKApiCity.serializer(), it) } } - if (hasObject(root, VKApiCommunity.COUNTRY)) { + if (hasObject(root, Fields.GROUP_FIELDS.COUNTRY)) { dto.country = - root[VKApiCommunity.COUNTRY]?.let { + root[Fields.GROUP_FIELDS.COUNTRY]?.let { kJson.decodeFromJsonElement(VKApiCountry.serializer(), it) } } - if (hasObject(root, VKApiCommunity.BAN_INFO)) { - val banInfo = root.getAsJsonObject(VKApiCommunity.BAN_INFO) + if (hasObject(root, Fields.GROUP_FIELDS.BAN_INFO)) { + val banInfo = root.getAsJsonObject(Fields.GROUP_FIELDS.BAN_INFO) dto.blacklisted = true dto.ban_end_date = optLong(banInfo, "end_date") dto.ban_comment = optString(banInfo, "comment") } - dto.description = optString(root, VKApiCommunity.DESCRIPTION) - dto.wiki_page = optString(root, VKApiCommunity.WIKI_PAGE) - dto.members_count = optInt(root, VKApiCommunity.MEMBERS_COUNT) - if (hasObject(root, VKApiCommunity.COUNTERS)) { - val counters = root.getAsJsonObject(VKApiCommunity.COUNTERS) + dto.description = optString(root, Fields.GROUP_FIELDS.DESCRIPTION) + dto.members_count = optInt(root, Fields.GROUP_FIELDS.MEMBERS_COUNT) + if (hasObject(root, Fields.GROUP_FIELDS.COUNTERS)) { + val counters = root.getAsJsonObject(Fields.GROUP_FIELDS.COUNTERS) dto.counters = counters?.let { kJson.decodeFromJsonElement(VKApiCommunity.Counters.serializer(), it) } } - if (hasObject(root, "chats_status")) { + if (hasObject(root, Fields.GROUP_FIELDS.CHATS_STATUS)) { if (dto.counters == null) { dto.counters = VKApiCommunity.Counters() } dto.counters?.chats = optInt( - root.getAsJsonObject("chats_status"), + root.getAsJsonObject(Fields.GROUP_FIELDS.CHATS_STATUS), "count", VKApiCommunity.Counters.NO_COUNTER ) } - dto.start_date = optLong(root, VKApiCommunity.START_DATE) - dto.finish_date = optLong(root, VKApiCommunity.FINISH_DATE) - dto.can_post = optBoolean(root, VKApiCommunity.CAN_POST) - dto.can_see_all_posts = optBoolean(root, VKApiCommunity.CAN_SEE_ALL_POSTS) - dto.can_upload_doc = optBoolean(root, VKApiCommunity.CAN_UPLOAD_DOC) - dto.can_upload_video = optBoolean(root, VKApiCommunity.CAN_UPLOAD_VIDEO) - dto.can_create_topic = optBoolean(root, VKApiCommunity.CAN_CTARE_TOPIC) - dto.is_favorite = optBoolean(root, VKApiCommunity.IS_FAVORITE) - dto.is_subscribed = optBoolean(root, VKApiCommunity.IS_SUBSCRIBED) - dto.status = VKStringUtils.unescape(optString(root, VKApiCommunity.STATUS)) + dto.start_date = optLong(root, Fields.GROUP_FIELDS.START_DATE) + dto.finish_date = optLong(root, Fields.GROUP_FIELDS.FINISH_DATE) + dto.can_post = optBoolean(root, Fields.GROUP_FIELDS.CAN_POST) + dto.can_see_all_posts = optBoolean(root, Fields.GROUP_FIELDS.CAN_SEE_ALL_POSTS) + dto.can_upload_doc = optBoolean(root, Fields.GROUP_FIELDS.CAN_UPLOAD_DOC) + dto.can_upload_video = optBoolean(root, Fields.GROUP_FIELDS.CAN_UPLOAD_VIDEO) + dto.can_create_topic = optBoolean(root, Fields.GROUP_FIELDS.CAN_CREATE_TOPIC) + dto.is_favorite = optBoolean(root, Fields.GROUP_FIELDS.IS_FAVORITE) + dto.is_subscribed = optBoolean(root, Fields.GROUP_FIELDS.IS_SUBSCRIBED) + dto.status = VKStringUtils.unescape(optString(root, Fields.GROUP_FIELDS.STATUS)) if (hasObject(root, "status_audio")) { dto.status_audio = root["status_audio"]?.let { kJson.decodeFromJsonElement(VKApiAudio.serializer(), it) } } dto.contacts = parseArray( - root.getAsJsonArray(VKApiCommunity.CONTACTS), + root.getAsJsonArray(Fields.GROUP_FIELDS.CONTACTS), null, VKApiCommunity.Contact.serializer() ) dto.links = parseArray( - root.getAsJsonArray(VKApiCommunity.LINKS), + root.getAsJsonArray(Fields.GROUP_FIELDS.LINKS), null, VKApiCommunity.Link.serializer() ) - dto.fixed_post = optInt(root, VKApiCommunity.FIXED_POST) - dto.main_album_id = optInt(root, VKApiCommunity.MAIN_ALBUM_ID) - dto.verified = optBoolean(root, VKApiCommunity.VERIFIED) - dto.site = optString(root, VKApiCommunity.SITE) - dto.activity = optString(root, VKApiCommunity.ACTIVITY) - dto.can_message = optBoolean(root, "can_message") - if (hasObject(root, "cover")) { - dto.cover = root["cover"]?.let { + dto.fixed_post = optInt(root, Fields.GROUP_FIELDS.FIXED_POST) + dto.main_album_id = optInt(root, Fields.GROUP_FIELDS.MAIN_ALBUM_ID) + dto.verified = optBoolean(root, Fields.GROUP_FIELDS.VERIFIED) + dto.site = optString(root, Fields.GROUP_FIELDS.SITE) + dto.activity = optString(root, Fields.GROUP_FIELDS.ACTIVITY) + dto.can_message = optBoolean(root, Fields.GROUP_FIELDS.CAN_MESSAGE) + dto.has_unseen_stories = optBoolean(root, Fields.GROUP_FIELDS.HAS_UNSEEN_STORIES) + if (hasObject(root, Fields.GROUP_FIELDS.COVER)) { + dto.cover = root[Fields.GROUP_FIELDS.COVER]?.let { kJson.decodeFromJsonElement(VKApiCover.serializer(), it) } } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/UserDtoAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/UserDtoAdapter.kt index afbcb006a..e7c09c9b4 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/UserDtoAdapter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/UserDtoAdapter.kt @@ -1,5 +1,6 @@ package dev.ragnarok.fenrir.api.adapters +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.model.* import dev.ragnarok.fenrir.api.util.VKStringUtils import dev.ragnarok.fenrir.kJson @@ -18,54 +19,54 @@ class UserDtoAdapter : AbsAdapter("VKApiUser") { val root = json.asJsonObject dto.id = optInt(root, "id") if (dto.id == 0) dto.id = optInt(root, "user_id") - dto.first_name = optString(root, "first_name") - dto.last_name = optString(root, "last_name") - dto.online = optBoolean(root, VKApiUser.Field.ONLINE) - dto.online_mobile = optBoolean(root, VKApiUser.Field.ONLINE_MOBILE) - dto.online_app = optInt(root, "online_app") - dto.photo_50 = optString(root, VKApiUser.Field.PHOTO_50, VKApiUser.CAMERA_50) - dto.photo_100 = optString(root, VKApiUser.Field.PHOTO_100) - dto.photo_200 = optString(root, VKApiUser.Field.PHOTO_200) - if (hasObject(root, VKApiUser.Field.LAST_SEEN)) { - val lastSeenRoot = root.getAsJsonObject(VKApiUser.Field.LAST_SEEN) + dto.first_name = optString(root, Fields.USER_FIELDS.FIRST_NAME) + dto.last_name = optString(root, Fields.USER_FIELDS.LAST_NAME) + dto.online = optBoolean(root, Fields.USER_FIELDS.ONLINE) + dto.online_mobile = optBoolean(root, Fields.USER_FIELDS.ONLINE_MOBILE) + dto.online_app = optInt(root, Fields.USER_FIELDS.ONLINE_APP) + dto.photo_50 = optString(root, Fields.USER_FIELDS.PHOTO_50, VKApiUser.CAMERA_50) + dto.photo_100 = optString(root, Fields.USER_FIELDS.PHOTO_100) + dto.photo_200 = optString(root, Fields.USER_FIELDS.PHOTO_200) + if (hasObject(root, Fields.USER_FIELDS.LAST_SEEN)) { + val lastSeenRoot = root.getAsJsonObject(Fields.USER_FIELDS.LAST_SEEN) dto.last_seen = optLong(lastSeenRoot, "time") - dto.platform = optInt(lastSeenRoot, "platform") + dto.platform = optInt(lastSeenRoot, Fields.USER_FIELDS.PLATFORM) } - dto.photo_max_orig = optString(root, VKApiUser.Field.PHOTO_MAX_ORIG) - dto.status = VKStringUtils.unescape(optString(root, VKApiUser.Field.STATUS)) - dto.bdate = optString(root, VKApiUser.Field.BDATE) - if (hasObject(root, VKApiUser.Field.CITY)) { - dto.city = root[VKApiUser.Field.CITY]?.let { + dto.photo_max_orig = optString(root, Fields.USER_FIELDS.PHOTO_MAX_ORIG) + dto.status = VKStringUtils.unescape(optString(root, Fields.USER_FIELDS.STATUS)) + dto.bdate = optString(root, Fields.USER_FIELDS.BDATE) + if (hasObject(root, Fields.USER_FIELDS.CITY)) { + dto.city = root[Fields.USER_FIELDS.CITY]?.let { kJson.decodeFromJsonElement(VKApiCity.serializer(), it) } } - if (hasObject(root, VKApiUser.Field.COUNTRY)) { + if (hasObject(root, Fields.USER_FIELDS.COUNTRY)) { dto.country = - root[VKApiUser.Field.COUNTRY]?.let { + root[Fields.USER_FIELDS.COUNTRY]?.let { kJson.decodeFromJsonElement(VKApiCountry.serializer(), it) } } dto.universities = parseArray( - root[VKApiUser.Field.UNIVERSITIES], + root[Fields.USER_FIELDS.UNIVERSITIES], null, VKApiUniversity.serializer() ) dto.schools = - parseArray(root[VKApiUser.Field.SCHOOLS], null, VKApiSchool.serializer()) + parseArray(root[Fields.USER_FIELDS.SCHOOLS], null, VKApiSchool.serializer()) dto.militaries = - parseArray(root[VKApiUser.Field.MILITARY], null, VKApiMilitary.serializer()) + parseArray(root[Fields.USER_FIELDS.MILITARY], null, VKApiMilitary.serializer()) dto.careers = - parseArray(root[VKApiUser.Field.CAREER], null, VKApiCareer.serializer()) + parseArray(root[Fields.USER_FIELDS.CAREER], null, VKApiCareer.serializer()) // status - dto.activity = optString(root, VKApiUser.Field.ACTIVITY) + dto.activity = optString(root, Fields.USER_FIELDS.ACTIVITY) if (hasObject(root, "status_audio")) { dto.status_audio = root["status_audio"]?.let { kJson.decodeFromJsonElement(VKApiAudio.serializer(), it) } } - if (hasObject(root, VKApiUser.Field.PERSONAL)) { - val personal = root.getAsJsonObject(VKApiUser.Field.PERSONAL) + if (hasObject(root, Fields.USER_FIELDS.PERSONAL)) { + val personal = root.getAsJsonObject(Fields.USER_FIELDS.PERSONAL) dto.smoking = optInt(personal, "smoking") dto.alcohol = optInt(personal, "alcohol") dto.political = optInt(personal, "political") @@ -83,8 +84,8 @@ class UserDtoAdapter : AbsAdapter("VKApiUser") { dto.facebook = optString(root, "facebook") dto.facebook_name = optString(root, "facebook_name") dto.livejournal = optString(root, "livejournal") - dto.site = optString(root, VKApiUser.Field.SITE) - dto.screen_name = optString(root, "screen_name", "id" + dto.id) + dto.site = optString(root, Fields.USER_FIELDS.SITE) + dto.screen_name = optString(root, Fields.USER_FIELDS.SCREEN_NAME, "id" + dto.id) dto.skype = optString(root, "skype") dto.mobile_phone = optString(root, "mobile_phone") dto.home_phone = optString(root, "home_phone") @@ -92,52 +93,49 @@ class UserDtoAdapter : AbsAdapter("VKApiUser") { dto.instagram = optString(root, "instagram") // personal info - dto.about = optString(root, VKApiUser.Field.ABOUT) - dto.activities = optString(root, VKApiUser.Field.ACTIVITIES) - dto.books = optString(root, VKApiUser.Field.BOOKS) - dto.games = optString(root, VKApiUser.Field.GAMES) - dto.interests = optString(root, VKApiUser.Field.INTERESTS) - dto.movies = optString(root, VKApiUser.Field.MOVIES) - dto.quotes = optString(root, VKApiUser.Field.QUOTES) - dto.tv = optString(root, VKApiUser.Field.TV) + dto.about = optString(root, Fields.USER_FIELDS.ABOUT) + dto.activities = optString(root, Fields.USER_FIELDS.ACTIVITIES) + dto.books = optString(root, Fields.USER_FIELDS.BOOKS) + dto.games = optString(root, Fields.USER_FIELDS.GAMES) + dto.interests = optString(root, Fields.USER_FIELDS.INTERESTS) + dto.movies = optString(root, Fields.USER_FIELDS.MOVIES) + dto.quotes = optString(root, Fields.USER_FIELDS.QUOTES) + dto.tv = optString(root, Fields.USER_FIELDS.TV) // settings - dto.nickname = optString(root, "nickname") - dto.domain = optString(root, "domain") - dto.can_post = optBoolean(root, VKApiUser.Field.CAN_POST) - dto.can_see_all_posts = optBoolean(root, VKApiUser.Field.CAN_SEE_ALL_POSTS) - dto.blacklisted_by_me = optBoolean(root, VKApiUser.Field.BLACKLISTED_BY_ME) - dto.can_write_private_message = optBoolean(root, VKApiUser.Field.CAN_WRITE_PRIVATE_MESSAGE) - dto.wall_comments = optBoolean(root, VKApiUser.Field.WALL_DEFAULT) + dto.domain = optString(root, Fields.USER_FIELDS.DOMAIN) + dto.can_post = optBoolean(root, Fields.USER_FIELDS.CAN_POST) + dto.can_see_all_posts = optBoolean(root, Fields.USER_FIELDS.CAN_SEE_ALL_POSTS) + dto.blacklisted_by_me = optBoolean(root, Fields.USER_FIELDS.BLACKLISTED_BY_ME) + dto.can_write_private_message = + optBoolean(root, Fields.USER_FIELDS.CAN_WRITE_PRIVATE_MESSAGE) + dto.wall_comments = optBoolean(root, Fields.USER_FIELDS.WALL_DEFAULT) val deactivated = optString(root, "deactivated") dto.is_deleted = "deleted" == deactivated dto.is_banned = "banned" == deactivated - dto.wall_default_owner = "owner" == optString(root, VKApiUser.Field.WALL_DEFAULT) - dto.verified = optBoolean(root, VKApiUser.Field.VERIFIED) - dto.can_access_closed = optBoolean(root, "can_access_closed") - dto.is_closed = optBoolean(root, "is_closed") + dto.wall_default_owner = "owner" == optString(root, Fields.USER_FIELDS.WALL_DEFAULT) + dto.verified = optBoolean(root, Fields.USER_FIELDS.VERIFIED) + dto.can_access_closed = optBoolean(root, Fields.USER_FIELDS.CAN_ACCESS_CLOSED) + dto.is_closed = optBoolean(root, Fields.USER_FIELDS.IS_CLOSED) // other - dto.sex = optInt(root, VKApiUser.Field.SEX) - if (hasObject(root, VKApiUser.Field.COUNTERS)) { + dto.sex = optInt(root, Fields.USER_FIELDS.SEX) + if (hasObject(root, Fields.USER_FIELDS.COUNTERS)) { dto.counters = - root[VKApiUser.Field.COUNTERS]?.let { + root[Fields.USER_FIELDS.COUNTERS]?.let { kJson.decodeFromJsonElement(VKApiUser.Counters.serializer(), it) } } - dto.relation = optInt(root, VKApiUser.Field.RELATION) + dto.relation = optInt(root, Fields.USER_FIELDS.RELATION) dto.relatives = parseArray( - root[VKApiUser.Field.RELATIVES], emptyList(), VKApiUser.Relative.serializer() + root[Fields.USER_FIELDS.RELATIVES], emptyList(), VKApiUser.Relative.serializer() ) - dto.home_town = optString(root, VKApiUser.Field.HOME_TOWN) - dto.photo_id = optString(root, "photo_id") - dto.blacklisted = optBoolean(root, "blacklisted") - dto.photo_200_orig = optString(root, "photo_200_orig") - dto.photo_400_orig = optString(root, "photo_400_orig") - dto.photo_max = optString(root, "photo_max") - dto.has_mobile = optBoolean(root, "has_mobile") - if (hasObject(root, "occupation")) { - dto.occupation = root["occupation"]?.let { + dto.home_town = optString(root, Fields.USER_FIELDS.HOME_TOWN) + dto.photo_id = optString(root, Fields.USER_FIELDS.PHOTO_ID) + dto.blacklisted = optBoolean(root, Fields.USER_FIELDS.BLACKLISTED) + dto.has_mobile = optBoolean(root, Fields.USER_FIELDS.HAS_MOBILE) + if (hasObject(root, Fields.USER_FIELDS.OCCUPATION)) { + dto.occupation = root[Fields.USER_FIELDS.OCCUPATION]?.let { kJson.decodeFromJsonElement(VKApiUser.Occupation.serializer(), it) } } @@ -145,16 +143,21 @@ class UserDtoAdapter : AbsAdapter("VKApiUser") { dto.relation_partner = root["relation_partner"]?.let { deserialize(it) } } - dto.music = optString(root, "music") - dto.can_see_audio = optBoolean(root, "can_see_audio") - dto.can_send_friend_request = optBoolean(root, "can_send_friend_request") - dto.is_favorite = optBoolean(root, "is_favorite") - dto.is_subscribed = optBoolean(root, "is_subscribed") - dto.timezone = optInt(root, "timezone") - dto.maiden_name = optString(root, "maiden_name") - dto.is_friend = optBoolean(root, "is_friend") - dto.friend_status = optInt(root, "friend_status") + dto.music = optString(root, Fields.USER_FIELDS.MUSIC) + dto.can_send_friend_request = optBoolean(root, Fields.USER_FIELDS.CAN_SEND_FRIEND_REQUEST) + dto.is_favorite = optBoolean(root, Fields.USER_FIELDS.IS_FAVORITE) + dto.is_subscribed = optBoolean(root, Fields.USER_FIELDS.IS_SUBSCRIBED) + dto.timezone = optInt(root, Fields.USER_FIELDS.TIMEZONE) + dto.maiden_name = optString(root, Fields.USER_FIELDS.MAIDEN_NAME) + dto.is_friend = optBoolean(root, Fields.USER_FIELDS.IS_FRIEND) + dto.friend_status = optInt(root, Fields.USER_FIELDS.FRIEND_STATUS) dto.role = optString(root, "role") + dto.has_unseen_stories = optBoolean(root, Fields.USER_FIELDS.HAS_UNSEEN_STORIES) + if (hasObject(root, Fields.USER_FIELDS.COVER)) { + dto.cover = root[Fields.USER_FIELDS.COVER]?.let { + kJson.decodeFromJsonElement(VKApiCover.serializer(), it) + } + } return dto } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/AccountApi.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/AccountApi.kt index ad51da362..91cfb37ef 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/AccountApi.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/AccountApi.kt @@ -1,9 +1,13 @@ package dev.ragnarok.fenrir.api.impl +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.IServiceProvider import dev.ragnarok.fenrir.api.TokenType import dev.ragnarok.fenrir.api.interfaces.IAccountApi -import dev.ragnarok.fenrir.api.model.* +import dev.ragnarok.fenrir.api.model.CountersDto +import dev.ragnarok.fenrir.api.model.RefreshToken +import dev.ragnarok.fenrir.api.model.VKApiProfileInfo +import dev.ragnarok.fenrir.api.model.VKApiProfileInfoResponse import dev.ragnarok.fenrir.api.model.response.AccountsBannedResponse import dev.ragnarok.fenrir.api.model.response.ContactsResponse import dev.ragnarok.fenrir.api.model.response.PushSettingsResponse @@ -171,7 +175,7 @@ internal class AccountApi(accountId: Int, provider: IServiceProvider) : return provideService(IAccountService(), TokenType.USER) .flatMap { service -> service - .getContactList(offset, count, 1, VKApiUser.ALL_FIELDS) + .getContactList(offset, count, 1, Fields.FIELDS_FULL_USER) .map(extractResponseWithErrorHandling()) } } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/AuthApi.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/AuthApi.kt index e8e7705d8..d509d8e7a 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/AuthApi.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/AuthApi.kt @@ -54,7 +54,8 @@ class AuthApi(private val service: IDirectLoginSeviceProvider) : IAuthApi { NeedValidationException( response.validationType, response.redirect_uri, - response.validation_sid + response.validation_sid, + response.errorDescription ) ) } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/FaveApi.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/FaveApi.kt index 0a5fff83c..61aea637a 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/FaveApi.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/FaveApi.kt @@ -1,6 +1,7 @@ package dev.ragnarok.fenrir.api.impl import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.IServiceProvider import dev.ragnarok.fenrir.api.TokenType import dev.ragnarok.fenrir.api.interfaces.IFaveApi @@ -8,7 +9,6 @@ import dev.ragnarok.fenrir.api.model.* import dev.ragnarok.fenrir.api.model.response.FavePageResponse import dev.ragnarok.fenrir.api.model.response.FavePostsResponse import dev.ragnarok.fenrir.api.services.IFaveService -import dev.ragnarok.fenrir.db.column.UserColumns import dev.ragnarok.fenrir.util.Utils.listEmptyIfNull import io.reactivex.rxjava3.core.Single @@ -38,7 +38,7 @@ internal class FaveApi(accountId: Int, provider: IServiceProvider) : AbsApi(acco override fun getVideos(offset: Int?, count: Int?): Single> { return provideService(IFaveService(), TokenType.USER) .flatMap { service -> - service.getVideos(offset, count, "video", 1, UserColumns.API_FIELDS) + service.getVideos(offset, count, "video", 1, Fields.FIELDS_BASE_OWNER) .map(extractResponseWithErrorHandling()) .flatMap { t -> val temp = listEmptyIfNull(t.items) @@ -54,7 +54,7 @@ internal class FaveApi(accountId: Int, provider: IServiceProvider) : AbsApi(acco override fun getArticles(offset: Int?, count: Int?): Single> { return provideService(IFaveService(), TokenType.USER) .flatMap { service -> - service.getArticles(offset, count, "article", 1, UserColumns.API_FIELDS) + service.getArticles(offset, count, "article", 1, Fields.FIELDS_BASE_OWNER) .map(extractResponseWithErrorHandling()) .flatMap { t -> val temp = listEmptyIfNull(t.items) @@ -80,7 +80,7 @@ internal class FaveApi(accountId: Int, provider: IServiceProvider) : AbsApi(acco count, "date", 1, - UserColumns.API_FIELDS + Fields.FIELDS_BASE_OWNER ) .map(extractResponseWithErrorHandling()) } @@ -89,7 +89,7 @@ internal class FaveApi(accountId: Int, provider: IServiceProvider) : AbsApi(acco override fun getPosts(offset: Int?, count: Int?): Single { return provideService(IFaveService(), TokenType.USER) .flatMap { service -> - service.getPosts(offset, count, "post", 1, UserColumns.API_FIELDS) + service.getPosts(offset, count, "post", 1, Fields.FIELDS_BASE_OWNER) .map(extractResponseWithErrorHandling()) } } @@ -97,7 +97,7 @@ internal class FaveApi(accountId: Int, provider: IServiceProvider) : AbsApi(acco override fun getLinks(offset: Int?, count: Int?): Single> { return provideService(IFaveService(), TokenType.USER) .flatMap { service -> - service.getLinks(offset, count, "link", 1, UserColumns.API_FIELDS) + service.getLinks(offset, count, "link", 1, Fields.FIELDS_BASE_OWNER) .map(extractResponseWithErrorHandling()) } } @@ -105,7 +105,7 @@ internal class FaveApi(accountId: Int, provider: IServiceProvider) : AbsApi(acco override fun getProducts(offset: Int?, count: Int?): Single> { return provideService(IFaveService(), TokenType.USER) .flatMap { service -> - service.getProducts(offset, count, "product", 1, UserColumns.API_FIELDS) + service.getProducts(offset, count, "product", 1, Fields.FIELDS_BASE_OWNER) .map(extractResponseWithErrorHandling()) .flatMap { t -> val temp = listEmptyIfNull(t.items) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/NewsfeedApi.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/NewsfeedApi.kt index 60b745f9e..80a8fea5f 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/NewsfeedApi.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/NewsfeedApi.kt @@ -1,6 +1,6 @@ package dev.ragnarok.fenrir.api.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.IServiceProvider import dev.ragnarok.fenrir.api.TokenType import dev.ragnarok.fenrir.api.interfaces.INewsfeedApi @@ -217,7 +217,7 @@ internal class NewsfeedApi(accountId: Int, provider: IServiceProvider) : service .getBanned( 1, - Constants.MAIN_OWNER_FIELDS + Fields.FIELDS_BASE_OWNER ) .map(extractResponseWithErrorHandling()) } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/PollsApi.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/PollsApi.kt index 476caf779..f522d1702 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/PollsApi.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/PollsApi.kt @@ -1,12 +1,12 @@ package dev.ragnarok.fenrir.api.impl +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.IServiceProvider import dev.ragnarok.fenrir.api.TokenType import dev.ragnarok.fenrir.api.interfaces.IPollsApi import dev.ragnarok.fenrir.api.model.VKApiPoll import dev.ragnarok.fenrir.api.model.VKApiUser import dev.ragnarok.fenrir.api.services.IPollsService -import dev.ragnarok.fenrir.db.column.UserColumns import dev.ragnarok.fenrir.util.Utils import dev.ragnarok.fenrir.util.serializeble.json.Json import io.reactivex.rxjava3.core.Single @@ -90,7 +90,7 @@ internal class PollsApi(accountId: Int, provider: IServiceProvider) : ids, offset, count, - UserColumns.API_FIELDS, + Fields.FIELDS_BASE_USER, null ) .map(extractResponseWithErrorHandling()) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/VKApiCommunity.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/VKApiCommunity.kt index 972c3033a..3d55ac268 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/VKApiCommunity.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/VKApiCommunity.kt @@ -89,11 +89,6 @@ class VKApiCommunity */ var description: String? = null - /** - * Name of the home wiki-page of the community. - */ - var wiki_page: String? = null - /** * Number of community members. */ @@ -194,6 +189,7 @@ class VKApiCommunity * информация о том, может ли текущий пользователь написать сообщение сообществу. Возможные значения: */ var can_message = false + var has_unseen_stories = false var cover: VKApiCover? = null /** @@ -330,103 +326,7 @@ class VKApiCommunity const val TYPE_EVENT = "event" const val PHOTO_50 = "http://vk.com/images/community_50.gif" const val PHOTO_100 = "http://vk.com/images/community_100.gif" - const val IS_FAVORITE = "is_favorite" - const val IS_SUBSCRIBED = "is_subscribed" - const val MAIN_ALBUM_ID = "main_album_id" - const val CAN_UPLOAD_DOC = "can_upload_doc" - const val CAN_CTARE_TOPIC = "can_upload_video" - const val CAN_UPLOAD_VIDEO = "can_create_topic" - const val BAN_INFO = "ban_info" - - /** - * Filed city from VK fields set - */ - const val CITY = "city" - - /** - * Filed country from VK fields set - */ - const val COUNTRY = "country" - - /** - * Filed description from VK fields set - */ - const val DESCRIPTION = "description" - - /** - * Filed wiki_page from VK fields set - */ - const val WIKI_PAGE = "wiki_page" - - /** - * Filed members_count from VK fields set - */ - const val MEMBERS_COUNT = "members_count" - - /** - * Filed counters from VK fields set - */ - const val COUNTERS = "counters" - - /** - * Filed start_date from VK fields set - */ - const val START_DATE = "start_date" - - /** - * Filed end_date from VK fields set - */ - const val FINISH_DATE = "finish_date" - - /** - * Filed can_post from VK fields set - */ - const val CAN_POST = "can_post" - - /** - * Filed can_see_all_posts from VK fields set - */ - const val CAN_SEE_ALL_POSTS = "can_see_all_posts" - - /** - * Filed status from VK fields set - */ - const val STATUS = "status" - - /** - * Filed contacts from VK fields set - */ - const val CONTACTS = "contacts" - - /** - * Filed links from VK fields set - */ - const val LINKS = "links" - - /** - * Filed fixed_post from VK fields set - */ - const val FIXED_POST = "fixed_post" - - /** - * Filed verified from VK fields set - */ - const val VERIFIED = "verified" - - /** - * Filed blacklisted from VK fields set - */ - const val BLACKLISTED = "blacklisted" - - /** - * Filed site from VK fields set - */ - const val SITE = "site" - - /** - * Filed activity from VK fields set - */ - const val ACTIVITY = "activity" + fun create(id: Int): VKApiCommunity { val community = VKApiCommunity() community.id = id diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/VKApiUser.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/VKApiUser.kt index 90aa9b345..ec8047b9a 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/VKApiUser.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/VKApiUser.kt @@ -215,11 +215,6 @@ class VKApiUser */ var screen_name: String? = null - /** - * Nickname of user. - */ - var nickname: String? = null - /** * User's activities */ @@ -348,25 +343,6 @@ class VKApiUser */ var blacklisted = false - /** - * url фотографии пользователя, имеющей ширину 200 пикселей. - * В случае отсутствия у пользователя фотографии возвращается http://vk.com/images/camera_a.gif. - */ - var photo_200_orig: String? = null - - /** - * url фотографии пользователя, имеющей ширину 400 пикселей. - * Если у пользователя отсутствует фотография такого размера, ответ не будет содержать этого поля. - */ - var photo_400_orig: String? = null - - /** - * url квадратной фотографии пользователя с максимальной шириной. - * Может быть возвращена фотография, имеющая ширину как 200, так и 100 пикселей. - * В случае отсутствия у пользователя фотографии возвращается http://vk.com/images/camera_b.gif. - */ - var photo_max: String? = null - /** * информация о том, известен ли номер мобильного телефона пользователя. * Возвращаемые значения: 1 — известен, 0 — не известен. @@ -390,12 +366,6 @@ class VKApiUser */ var music: String? = null - /** - * информация о том, разрешено ли видеть чужие аудиозаписи на стене пользователя. - * Возвращаемые значения: 1 —разрешено, 0 — не разрешено. - */ - var can_see_audio = false - /** * информация о том, будет ли отправлено уведомление пользователю о заявке в друзья. * Возвращаемые значения: 1 — уведомление будет отправлено, 0 — уведомление не будет оптравлено. @@ -423,6 +393,10 @@ class VKApiUser */ var is_friend = false + var has_unseen_stories = false + + var cover: VKApiCover? = null + /** * статус дружбы с пользователем: * 0 – пользователь не является другом, @@ -452,213 +426,6 @@ class VKApiUser override val fullName: String get() = if (first_name.isNullOrEmpty() && last_name.isNullOrEmpty()) "[id $id]" else "$first_name $last_name" - object Field { - /** - * Field name for [.online] param. - */ - const val ONLINE = "online" - - /** - * Field name for [.online_mobile] param. - */ - const val ONLINE_MOBILE = "online_mobile" - - /** - * Field name for [.photo_50] param. - */ - const val PHOTO_50 = "photo_50" - - /** - * Field name for [.photo_100] param. - */ - const val PHOTO_100 = "photo_100" - - /** - * Field name for [.photo_200] param. - */ - const val PHOTO_200 = "photo_200" - - /** - * Filed last_seen from VK fields set - */ - const val LAST_SEEN = "last_seen" - - /** - * Filed photo_max_orig - */ - const val PHOTO_MAX_ORIG = "photo_max_orig" - - /** - * Filed photo_max_orig - */ - const val STATUS = "status" - - /** - * Filed bdate from VK fields set - */ - const val BDATE = "bdate" - - /** - * Filed city from VK fields set - */ - const val CITY = "city" - - /** - * Filed country from VK fields set - */ - const val COUNTRY = "country" - - /** - * Filed universities from VK fields set - */ - const val UNIVERSITIES = "universities" - - /** - * Filed schools from VK fields set - */ - const val SCHOOLS = "schools" - - /** - * Filed military from VK fields set - */ - const val MILITARY = "military" - - /** - * Filed military from VK fields set - */ - const val CAREER = "career" - - /** - * Filed activity from VK fields set - */ - const val ACTIVITY = "activity" - - /** - * Filed personal from VK fields set - */ - const val PERSONAL = "personal" - - /** - * Filed sex from VK fields set - */ - const val SEX = "sex" - - /** - * Filed site from VK fields set - */ - const val SITE = "site" - - /** - * Filed contacts from VK fields set - */ - const val CONTACTS = "contacts" - - /** - * Filed can_post from VK fields set - */ - const val CAN_POST = "can_post" - - /** - * Filed can_see_all_posts from VK fields set - */ - const val CAN_SEE_ALL_POSTS = "can_see_all_posts" - - /** - * Filed can_write_private_message from VK fields set - */ - const val CAN_WRITE_PRIVATE_MESSAGE = "can_write_private_message" - - /** - * Filed relation from VK fields set - */ - const val RELATION = "relation" - - /** - * Filed counters from VK fields set - */ - const val COUNTERS = "counters" - - /** - * Filed activities from VK fields set - */ - const val ACTIVITIES = "activities" - - /** - * Filed interests from VK fields set - */ - const val INTERESTS = "interests" - - /** - * Filed movies from VK fields set - */ - const val MOVIES = "movies" - - /** - * Filed tv from VK fields set - */ - const val TV = "tv" - - /** - * Filed books from VK fields set - */ - const val BOOKS = "books" - - /** - * Filed games from VK fields set - */ - const val GAMES = "games" - - /** - * Filed about from VK fields set - */ - const val ABOUT = "about" - - /** - * Filed quotes from VK fields set - */ - const val QUOTES = "quotes" - - /** - * Filed connections from VK fields set - */ - const val CONNECTIONS = "connections" - - /** - * Filed relatives from VK fields set - */ - const val RELATIVES = "relatives" - - /** - * Filed wall_default from VK fields set - */ - const val WALL_DEFAULT = "wall_default" - - /** - * Filed verified from VK fields set - */ - const val VERIFIED = "verified" - - /** - * Filed screen_name from VK fields set - */ - const val SCREEN_NAME = "screen_name" - - /** - * Filed blacklisted_by_me from VK fields set - */ - const val BLACKLISTED_BY_ME = "blacklisted_by_me" - - /** - * Filed blacklisted_by_me from VK fields set - */ - const val DOMAIN = "domain" - - /** - * Filed blacklisted_by_me from VK fields set - */ - const val HOME_TOWN = "home_town" - } - object Platform { const val MOBILE = 1 const val IPHONE = 2 @@ -753,8 +520,6 @@ class VKApiUser const val FRIEND_STATUS_REQUEST_SENT = 1 const val FRIEND_STATUS_HAS_INPUT_REQUEST = 2 const val FRIEND_STATUS_IS_FRIEDND = 3 - const val ALL_FIELDS = - "about,activities,bdate,blacklisted,blacklisted_by_me,books,can_access_closed,can_post,can_see_all_posts,can_see_audio,can_write_private_message,career,city,common_count,connections,contacts,counters,country,domain,first_name,education,friend_status,games,has_mobile,interests,is_closed,is_favorite,is_friend,is_subscribed,last_name,last_seen,maiden_name,military,movies,music,occupation,online,online_app,online_mobile,personal,photo_100,photo_200,photo_200_orig,photo_400_orig,photo_50,photo_id,photo_max,photo_max_orig,quotes,relation,relatives,schools,screen_name,sex,site,status,timezone,tv,universities,verified" fun create(id: Int): VKApiUser { val user = VKApiUser() diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/DBHelper.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/DBHelper.kt index 049dc132b..bb354d4e0 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/DBHelper.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/DBHelper.kt @@ -21,6 +21,7 @@ class DBHelper private constructor(context: Context, aid: Int) : } } + /* private fun insertColumn( db: SQLiteDatabase, tableName: String, @@ -34,21 +35,7 @@ class DBHelper private constructor(context: Context, aid: Int) : private fun dropColumn(db: SQLiteDatabase, tableName: String, column: String) { db.execSQL("ALTER TABLE $tableName DROP COLUMN $column;") } - - private fun createKeysTableIfNotExist(db: SQLiteDatabase) { - val sql = "CREATE TABLE IF NOT EXISTS [" + KeyColumns.TABLENAME + "] (\n" + - " [" + BaseColumns._ID + "] INTEGER PRIMARY KEY AUTOINCREMENT, " + - " [" + KeyColumns.VERSION + "] INTEGER, " + - " [" + KeyColumns.PEER_ID + "] INTEGER, " + - " [" + KeyColumns.SESSION_ID + "] INTEGER, " + - " [" + KeyColumns.DATE + "] INTEGER, " + - " [" + KeyColumns.START_SESSION_MESSAGE_ID + "] INTEGER, " + - " [" + KeyColumns.END_SESSION_MESSAGE_ID + "] INTEGER, " + - " [" + KeyColumns.OUT_KEY + "] TEXT, " + - " [" + KeyColumns.IN_KEY + "] TEXT," + - " CONSTRAINT [] UNIQUE ([" + KeyColumns.SESSION_ID + "]) ON CONFLICT REPLACE);" - db.execSQL(sql) - } + */ override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { if (oldVersion != Constants.DATABASE_FENRIR_VERSION) { @@ -154,6 +141,21 @@ class DBHelper private constructor(context: Context, aid: Int) : db.endTransaction() } + private fun createKeysTableIfNotExist(db: SQLiteDatabase) { + val sql = "CREATE TABLE IF NOT EXISTS [" + KeyColumns.TABLENAME + "] (\n" + + " [" + BaseColumns._ID + "] INTEGER PRIMARY KEY AUTOINCREMENT, " + + " [" + KeyColumns.VERSION + "] INTEGER, " + + " [" + KeyColumns.PEER_ID + "] INTEGER, " + + " [" + KeyColumns.SESSION_ID + "] INTEGER, " + + " [" + KeyColumns.DATE + "] INTEGER, " + + " [" + KeyColumns.START_SESSION_MESSAGE_ID + "] INTEGER, " + + " [" + KeyColumns.END_SESSION_MESSAGE_ID + "] INTEGER, " + + " [" + KeyColumns.OUT_KEY + "] TEXT, " + + " [" + KeyColumns.IN_KEY + "] TEXT," + + " CONSTRAINT [] UNIQUE ([" + KeyColumns.SESSION_ID + "]) ON CONFLICT REPLACE);" + db.execSQL(sql) + } + private fun createZeroMessageProtectionTriggers(db: SQLiteDatabase) { val sqlUpdate = "CREATE TRIGGER zero_msg_upd BEFORE UPDATE ON " + MessageColumns.TABLENAME + " FOR EACH ROW " + @@ -597,6 +599,7 @@ class DBHelper private constructor(context: Context, aid: Int) : " [" + UserColumns.IS_BLACK_LISTED + "] BOOLEAN, " + " [" + UserColumns.IS_CAN_ACCESS_CLOSED + "] BOOLEAN, " + " [" + UserColumns.IS_VERIFIED + "] BOOLEAN, " + + " [" + UserColumns.HAS_UNSEEN_STORIES + "] BOOLEAN, " + " CONSTRAINT [] PRIMARY KEY([" + BaseColumns._ID + "]) ON CONFLICT REPLACE);" db.execSQL(sql) } @@ -696,6 +699,7 @@ class DBHelper private constructor(context: Context, aid: Int) : " [" + GroupColumns.CAN_ADD_TOPICS + "] BOOLEAN, " + " [" + GroupColumns.TOPICS_ORDER + "] BOOLEAN, " + " [" + GroupColumns.IS_BLACK_LISTED + "] BOOLEAN, " + + " [" + GroupColumns.HAS_UNSEEN_STORIES + "] BOOLEAN, " + " CONSTRAINT [] PRIMARY KEY([" + BaseColumns._ID + "]) ON CONFLICT REPLACE);" db.execSQL(sql) } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/FenrirContentProvider.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/FenrirContentProvider.kt index 912af5f11..801ec623a 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/FenrirContentProvider.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/FenrirContentProvider.kt @@ -241,7 +241,8 @@ class FenrirContentProvider : ContentProvider() { Uri.parse("content://$AUTHORITY/$FRIEND_LISTS_PATH") private val KEYS_CONTENT_URI = Uri.parse("content://$AUTHORITY/$KEYS_PATH") private const val AID = "aid" - private var sUsersProjectionMap: MutableMap = HashMap() + + private val sUsersProjectionMap: MutableMap private val sMessagesProjectionMap: MutableMap private val sMessagesAttachmentsProjectionMap: MutableMap private val sPhotosProjectionMap: MutableMap @@ -276,6 +277,56 @@ class FenrirContentProvider : ContentProvider() { private val sFriendListsProjectionMap: MutableMap private val sKeysProjectionMap: MutableMap + /* + private fun testProjectionMapsArgs(vararg maps: MutableMap) { + for (i in maps) { + for (s in i) { + if (!s.value.contains(s.key)) { + throw Exception("${s.key} = ${s.value}") + } + } + } + } + + fun testProjectionMaps() { + testProjectionMapsArgs( + sUsersProjectionMap, + sMessagesProjectionMap, + sMessagesAttachmentsProjectionMap, + sPhotosProjectionMap, + sPhotosExtendedProjectionMap, + sDialogsProjectionMap, + sPeersProjectionMap, + sDocsProjectionMap, + sVideosProjectionMap, + sPostsProjectionMap, + sPostsMessagesAttachmentsProjectionMap, + sGroupsProjectionMap, + sGroupsDetProjectionMap, + sCommentsProjectionMap, + sCommentsMessagesAttachmentsProjectionMap, + sPhotoAlbumsProjectionMap, + sNewsProjectionMap, + sVideoAlbumsProjectionMap, + sTopicsProjectionMap, + sNoticationsProjectionMap, + sUserDetProjectionMap, + sFavePhotosProjectionMap, + sFaveVideosProjectionMap, + sFaveUsersProjectionMap, + sFaveGroupsProjectionMap, + sFaveLinksProjectionMap, + sFavePostsProjectionMap, + sFaveArticlesProjectionMap, + sFaveProductsProjectionMap, + sCountriesProjectionMap, + sFeedListsProjectionMap, + sFriendListsProjectionMap, + sKeysProjectionMap, + sRelativeshipProjectionMap + ) + } + */ fun getKeysContentUriFor(aid: Int): Uri { return appendAccountId(KEYS_CONTENT_URI, aid) @@ -517,6 +568,7 @@ class FenrirContentProvider : ContentProvider() { init { //Setup projection maps + sUsersProjectionMap = HashMap() sUsersProjectionMap[BaseColumns._ID] = UserColumns.FULL_ID sUsersProjectionMap[UserColumns.FIRST_NAME] = UserColumns.FULL_FIRST_NAME sUsersProjectionMap[UserColumns.LAST_NAME] = @@ -530,6 +582,8 @@ class FenrirContentProvider : ContentProvider() { sUsersProjectionMap[UserColumns.PHOTO_200] = UserColumns.FULL_PHOTO_200 sUsersProjectionMap[UserColumns.PHOTO_MAX] = UserColumns.FULL_PHOTO_MAX sUsersProjectionMap[UserColumns.LAST_SEEN] = UserColumns.FULL_LAST_SEEN + sUsersProjectionMap[UserColumns.HAS_UNSEEN_STORIES] = + UserColumns.FULL_HAS_UNSEEN_STORIES sUsersProjectionMap[UserColumns.PLATFORM] = UserColumns.FULL_PLATFORM sUsersProjectionMap[UserColumns.USER_STATUS] = UserColumns.FULL_USER_STATUS @@ -548,6 +602,7 @@ class FenrirContentProvider : ContentProvider() { sUsersProjectionMap[UserColumns.IS_VERIFIED] = UserColumns.FULL_IS_VERIFIED sUsersProjectionMap[UserColumns.MAIDEN_NAME] = UserColumns.FULL_MAIDEN_NAME sUsersProjectionMap[UserColumns.BDATE] = UserColumns.FULL_BDATE + sRelativeshipProjectionMap = HashMap() sRelativeshipProjectionMap[BaseColumns._ID] = RelationshipColumns.FULL_ID sRelativeshipProjectionMap[RelationshipColumns.OBJECT_ID] = @@ -573,6 +628,8 @@ class FenrirContentProvider : ContentProvider() { UserColumns.FULL_PHOTO_200 + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_PHOTO_200 sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_PHOTO_MAX] = UserColumns.FULL_PHOTO_MAX + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_PHOTO_MAX + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_HAS_UNSEEN_STORIES] = + UserColumns.FULL_HAS_UNSEEN_STORIES + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_HAS_UNSEEN_STORIES sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_LAST_SEEN] = UserColumns.FULL_LAST_SEEN + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_LAST_SEEN sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_PLATFORM] = @@ -585,20 +642,21 @@ class FenrirContentProvider : ContentProvider() { UserColumns.FULL_IS_FRIEND + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_IS_FRIEND sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_FRIEND_STATUS] = UserColumns.FULL_FRIEND_STATUS + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_FRIEND_STATUS - sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_WRITE_MESSAGE_STATUS] = - UserColumns.FULL_WRITE_MESSAGE_STATUS + " AS " + RelationshipColumns.FOREIGN_SUBJECT_WRITE_MESSAGE_STATUS - sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_IS_USER_BLACK_LIST] = - UserColumns.FULL_IS_USER_BLACK_LIST + " AS " + RelationshipColumns.FOREIGN_SUBJECT_IS_USER_BLACK_LIST - sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_IS_BLACK_LISTED] = - UserColumns.FULL_IS_BLACK_LISTED + " AS " + RelationshipColumns.FOREIGN_SUBJECT_IS_BLACK_LISTED - sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_IS_CAN_ACCESS_CLOSED] = - UserColumns.FULL_IS_CAN_ACCESS_CLOSED + " AS " + RelationshipColumns.FOREIGN_SUBJECT_IS_CAN_ACCESS_CLOSED - sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_IS_VERIFIED] = - UserColumns.FULL_IS_VERIFIED + " AS " + RelationshipColumns.FOREIGN_SUBJECT_IS_VERIFIED - sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_MAIDEN_NAME] = - UserColumns.FULL_MAIDEN_NAME + " AS " + RelationshipColumns.FOREIGN_SUBJECT_MAIDEN_NAME - sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_BDATE] = - UserColumns.FULL_BDATE + " AS " + RelationshipColumns.FOREIGN_SUBJECT_BDATE + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_WRITE_MESSAGE_STATUS] = + UserColumns.FULL_WRITE_MESSAGE_STATUS + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_WRITE_MESSAGE_STATUS + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_IS_USER_BLACK_LIST] = + UserColumns.FULL_IS_USER_BLACK_LIST + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_IS_USER_BLACK_LIST + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_IS_BLACK_LISTED] = + UserColumns.FULL_IS_BLACK_LISTED + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_IS_BLACK_LISTED + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_IS_CAN_ACCESS_CLOSED] = + UserColumns.FULL_IS_CAN_ACCESS_CLOSED + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_IS_CAN_ACCESS_CLOSED + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_IS_VERIFIED] = + UserColumns.FULL_IS_VERIFIED + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_IS_VERIFIED + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_MAIDEN_NAME] = + UserColumns.FULL_MAIDEN_NAME + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_MAIDEN_NAME + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_USER_BDATE] = + UserColumns.FULL_BDATE + " AS " + RelationshipColumns.FOREIGN_SUBJECT_USER_BDATE + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_GROUP_NAME] = GroupColumns.FULL_NAME + " AS " + RelationshipColumns.FOREIGN_SUBJECT_GROUP_NAME sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_GROUP_SCREEN_NAME] = @@ -615,6 +673,8 @@ class FenrirContentProvider : ContentProvider() { GroupColumns.FULL_IS_BLACK_LISTED + " AS " + RelationshipColumns.FOREIGN_SUBJECT_GROUP_IS_BLACK_LISTED sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_GROUP_IS_VERIFIED] = GroupColumns.FULL_IS_VERIFIED + " AS " + RelationshipColumns.FOREIGN_SUBJECT_GROUP_IS_VERIFIED + sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_GROUP_HAS_UNSEEN_STORIES] = + GroupColumns.FULL_HAS_UNSEEN_STORIES + " AS " + RelationshipColumns.FOREIGN_SUBJECT_GROUP_HAS_UNSEEN_STORIES sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_GROUP_IS_ADMIN] = GroupColumns.FULL_IS_ADMIN + " AS " + RelationshipColumns.FOREIGN_SUBJECT_GROUP_IS_ADMIN sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_GROUP_ADMIN_LEVEL] = @@ -627,6 +687,7 @@ class FenrirContentProvider : ContentProvider() { GroupColumns.FULL_MEMBER_STATUS + " AS " + RelationshipColumns.FOREIGN_SUBJECT_GROUP_MEMBER_STATUS sRelativeshipProjectionMap[RelationshipColumns.FOREIGN_SUBJECT_GROUP_TYPE] = GroupColumns.FULL_TYPE + " AS " + RelationshipColumns.FOREIGN_SUBJECT_GROUP_TYPE + sMessagesProjectionMap = HashMap() sMessagesProjectionMap[MessageColumns._ID] = MessageColumns.FULL_ID sMessagesProjectionMap[MessageColumns.PEER_ID] = MessageColumns.FULL_PEER_ID @@ -669,12 +730,14 @@ class FenrirContentProvider : ContentProvider() { sMessagesProjectionMap[MessageColumns.PAYLOAD] = MessageColumns.FULL_PAYLOAD sMessagesProjectionMap[MessageColumns.KEYBOARD] = MessageColumns.FULL_KEYBOARD + sMessagesAttachmentsProjectionMap = HashMap() sMessagesAttachmentsProjectionMap[BaseColumns._ID] = MessagesAttachmentsColumns.FULL_ID sMessagesAttachmentsProjectionMap[MessagesAttachmentsColumns.M_ID] = MessagesAttachmentsColumns.FULL_M_ID sMessagesAttachmentsProjectionMap[MessagesAttachmentsColumns.DATA] = MessagesAttachmentsColumns.FULL_DATA + sPhotosProjectionMap = HashMap() sPhotosProjectionMap[BaseColumns._ID] = PhotosColumns.FULL_ID @@ -705,6 +768,7 @@ class FenrirContentProvider : ContentProvider() { PhotosColumns.FULL_ACCESS_KEY sPhotosProjectionMap[PhotosColumns.DELETED] = PhotosColumns.FULL_DELETED + sPhotosExtendedProjectionMap = HashMap() sPhotosExtendedProjectionMap[BaseColumns._ID] = PhotosExtendedColumns.FULL_ID @@ -744,6 +808,7 @@ class FenrirContentProvider : ContentProvider() { PhotosExtendedColumns.FULL_ACCESS_KEY sPhotosExtendedProjectionMap[PhotosExtendedColumns.DELETED] = PhotosExtendedColumns.FULL_DELETED + sDialogsProjectionMap = HashMap() sDialogsProjectionMap[BaseColumns._ID] = DialogsColumns.FULL_ID @@ -782,6 +847,7 @@ class FenrirContentProvider : ContentProvider() { MessageColumns.FULL_ACTION + " AS " + DialogsColumns.FOREIGN_MESSAGE_ACTION sDialogsProjectionMap[DialogsColumns.FOREIGN_MESSAGE_ENCRYPTED] = MessageColumns.FULL_ENCRYPTED + " AS " + DialogsColumns.FOREIGN_MESSAGE_ENCRYPTED + sPeersProjectionMap = HashMap() sPeersProjectionMap[BaseColumns._ID] = PeersColumns.FULL_ID sPeersProjectionMap[PeersColumns.UNREAD] = @@ -803,6 +869,7 @@ class FenrirContentProvider : ContentProvider() { sPeersProjectionMap[PeersColumns.KEYBOARD] = PeersColumns.FULL_KEYBOARD sPeersProjectionMap[PeersColumns.MAJOR_ID] = PeersColumns.FULL_MAJOR_ID sPeersProjectionMap[PeersColumns.MINOR_ID] = PeersColumns.FULL_MINOR_ID + sDocsProjectionMap = HashMap() sDocsProjectionMap[BaseColumns._ID] = DocColumns.FULL_ID sDocsProjectionMap[DocColumns.DOC_ID] = DocColumns.FULL_DOC_ID @@ -818,6 +885,7 @@ class FenrirContentProvider : ContentProvider() { sDocsProjectionMap[DocColumns.DATE] = DocColumns.FULL_DATE sDocsProjectionMap[DocColumns.TYPE] = DocColumns.FULL_TYPE sDocsProjectionMap[DocColumns.ACCESS_KEY] = DocColumns.FULL_ACCESS_KEY + sVideosProjectionMap = HashMap() sVideosProjectionMap[BaseColumns._ID] = VideoColumns.FULL_ID @@ -880,6 +948,7 @@ class FenrirContentProvider : ContentProvider() { sVideosProjectionMap[VideoColumns.CAN_EDIT] = VideoColumns.FULL_CAN_EDIT sVideosProjectionMap[VideoColumns.CAN_ADD] = VideoColumns.FULL_CAN_ADD + sPostsProjectionMap = HashMap() sPostsProjectionMap[BaseColumns._ID] = PostsColumns.FULL_ID sPostsProjectionMap[PostsColumns.POST_ID] = @@ -920,6 +989,7 @@ class FenrirContentProvider : ContentProvider() { PostsColumns.FULL_DELETED sPostsProjectionMap[PostsColumns.POST_SOURCE] = PostsColumns.FULL_POST_SOURCE sPostsProjectionMap[PostsColumns.VIEWS] = PostsColumns.FULL_VIEWS + sPostsMessagesAttachmentsProjectionMap = HashMap() sPostsMessagesAttachmentsProjectionMap[BaseColumns._ID] = WallAttachmentsColumns.FULL_ID @@ -927,10 +997,13 @@ class FenrirContentProvider : ContentProvider() { WallAttachmentsColumns.FULL_P_ID sPostsMessagesAttachmentsProjectionMap[WallAttachmentsColumns.DATA] = WallAttachmentsColumns.FULL_DATA + sGroupsProjectionMap = HashMap() sGroupsProjectionMap[BaseColumns._ID] = GroupColumns.FULL_ID sGroupsProjectionMap[GroupColumns.NAME] = GroupColumns.FULL_NAME sGroupsProjectionMap[GroupColumns.SCREEN_NAME] = GroupColumns.FULL_SCREEN_NAME + sGroupsProjectionMap[GroupColumns.HAS_UNSEEN_STORIES] = + GroupColumns.FULL_HAS_UNSEEN_STORIES sGroupsProjectionMap[GroupColumns.IS_CLOSED] = GroupColumns.FULL_IS_CLOSED sGroupsProjectionMap[GroupColumns.IS_VERIFIED] = GroupColumns.FULL_IS_VERIFIED @@ -950,6 +1023,7 @@ class FenrirContentProvider : ContentProvider() { GroupColumns.FULL_CAN_ADD_TOPICS sGroupsProjectionMap[GroupColumns.TOPICS_ORDER] = GroupColumns.FULL_TOPICS_ORDER sGroupsProjectionMap[GroupColumns.IS_BLACK_LISTED] = GroupColumns.FULL_IS_BLACK_LISTED + sCommentsProjectionMap = HashMap() sCommentsProjectionMap[BaseColumns._ID] = CommentsColumns.FULL_ID sCommentsProjectionMap[CommentsColumns.COMMENT_ID] = CommentsColumns.FULL_COMMENT_ID @@ -981,6 +1055,7 @@ class FenrirContentProvider : ContentProvider() { CommentsColumns.FULL_SOURCE_TYPE sCommentsProjectionMap[CommentsColumns.SOURCE_ACCESS_KEY] = CommentsColumns.FULL_SOURCE_ACCESS_KEY + sCommentsMessagesAttachmentsProjectionMap = HashMap() sCommentsMessagesAttachmentsProjectionMap[BaseColumns._ID] = CommentsAttachmentsColumns.FULL_ID @@ -988,6 +1063,7 @@ class FenrirContentProvider : ContentProvider() { CommentsAttachmentsColumns.FULL_C_ID sCommentsMessagesAttachmentsProjectionMap[CommentsAttachmentsColumns.DATA] = CommentsAttachmentsColumns.FULL_DATA + sPhotoAlbumsProjectionMap = HashMap() sPhotoAlbumsProjectionMap[PhotoAlbumsColumns.ALBUM_ID] = PhotoAlbumsColumns.FULL_ALBUM_ID @@ -1027,6 +1103,7 @@ class FenrirContentProvider : ContentProvider() { //sPollProjectionMap.put(PollColumns.ANONYMOUS, PollColumns.FULL_ANONYMOUS); //sPollProjectionMap.put(PollColumns.IS_BOARD, PollColumns.FULL_IS_BOARD); //sPollProjectionMap.put(PollColumns.ANSWERS, PollColumns.FULL_ANSWERS); + sNewsProjectionMap = HashMap() sNewsProjectionMap[BaseColumns._ID] = NewsColumns.FULL_ID sNewsProjectionMap[NewsColumns.TYPE] = NewsColumns.FULL_TYPE @@ -1062,11 +1139,13 @@ class FenrirContentProvider : ContentProvider() { sNewsProjectionMap[NewsColumns.ATTACHMENTS_BLOB] = NewsColumns.FULL_ATTACHMENTS_BLOB sNewsProjectionMap[NewsColumns.VIEWS] = NewsColumns.FULL_VIEWS + sGroupsDetProjectionMap = HashMap() sGroupsDetProjectionMap[BaseColumns._ID] = GroupsDetColumns.FULL_ID sGroupsDetProjectionMap[GroupsDetColumns.DATA] = GroupsDetColumns.FULL_DATA + sVideoAlbumsProjectionMap = HashMap() sVideoAlbumsProjectionMap[BaseColumns._ID] = VideoAlbumsColumns.FULL_ID @@ -1082,6 +1161,7 @@ class FenrirContentProvider : ContentProvider() { sVideoAlbumsProjectionMap[VideoAlbumsColumns.UPDATE_TIME] = VideoAlbumsColumns.FULL_UPDATE_TIME sVideoAlbumsProjectionMap[VideoAlbumsColumns.PRIVACY] = VideoAlbumsColumns.FULL_PRIVACY + sTopicsProjectionMap = HashMap() sTopicsProjectionMap[BaseColumns._ID] = TopicsColumns.FULL_ID sTopicsProjectionMap[TopicsColumns.TOPIC_ID] = TopicsColumns.FULL_TOPIC_ID @@ -1103,15 +1183,18 @@ class FenrirContentProvider : ContentProvider() { sTopicsProjectionMap[TopicsColumns.LAST_COMMENT] = TopicsColumns.FULL_LAST_COMMENT sTopicsProjectionMap[TopicsColumns.ATTACHED_POLL] = TopicsColumns.FULL_ATTACHED_POLL //sTopicsProjectionMap.put(TopicsColumns.POLL_ID, TopicsColumns.FULL_POLL_ID); + sNoticationsProjectionMap = HashMap() sNoticationsProjectionMap[BaseColumns._ID] = NotificationColumns.FULL_ID sNoticationsProjectionMap[NotificationColumns.DATE] = NotificationColumns.FULL_DATE sNoticationsProjectionMap[NotificationColumns.CONTENT_PACK] = NotificationColumns.FULL_CONTENT_PACK + sUserDetProjectionMap = HashMap() sUserDetProjectionMap[BaseColumns._ID] = UsersDetColumns.FULL_ID sUserDetProjectionMap[UsersDetColumns.DATA] = UsersDetColumns.FULL_DATA + sFavePhotosProjectionMap = HashMap() sFavePhotosProjectionMap[BaseColumns._ID] = FavePhotosColumns.FULL_ID @@ -1121,19 +1204,23 @@ class FenrirContentProvider : ContentProvider() { FavePhotosColumns.FULL_POST_ID sFavePhotosProjectionMap[FavePhotosColumns.PHOTO] = FavePhotosColumns.FULL_PHOTO + sFaveVideosProjectionMap = HashMap() sFaveVideosProjectionMap[BaseColumns._ID] = FaveVideosColumns.FULL_ID sFaveVideosProjectionMap[FaveVideosColumns.VIDEO] = FaveVideosColumns.FULL_VIDEO + sFaveArticlesProjectionMap = HashMap() sFaveArticlesProjectionMap[BaseColumns._ID] = FaveArticlesColumns.FULL_ID sFaveArticlesProjectionMap[FaveArticlesColumns.ARTICLE] = FaveArticlesColumns.FULL_ARTICLE + sFaveProductsProjectionMap = HashMap() sFaveProductsProjectionMap[BaseColumns._ID] = FaveProductColumns.FULL_ID sFaveProductsProjectionMap[FaveProductColumns.PRODUCT] = FaveProductColumns.FULL_PRODUCT + sFaveUsersProjectionMap = HashMap() sFaveUsersProjectionMap[BaseColumns._ID] = FavePageColumns.FULL_ID @@ -1141,6 +1228,7 @@ class FenrirContentProvider : ContentProvider() { sFaveUsersProjectionMap[FavePageColumns.DESCRIPTION] = FavePageColumns.DESCRIPTION sFaveUsersProjectionMap[FavePageColumns.FAVE_TYPE] = FavePageColumns.FAVE_TYPE + sFaveGroupsProjectionMap = HashMap() sFaveGroupsProjectionMap[BaseColumns._ID] = FavePageColumns.FULL_GROUPS_ID @@ -1148,6 +1236,7 @@ class FenrirContentProvider : ContentProvider() { FavePageColumns.UPDATED_TIME sFaveGroupsProjectionMap[FavePageColumns.DESCRIPTION] = FavePageColumns.DESCRIPTION sFaveGroupsProjectionMap[FavePageColumns.FAVE_TYPE] = FavePageColumns.FAVE_TYPE + sFaveLinksProjectionMap = HashMap() sFaveLinksProjectionMap[BaseColumns._ID] = FaveLinksColumns.FULL_ID @@ -1159,13 +1248,16 @@ class FenrirContentProvider : ContentProvider() { FaveLinksColumns.FULL_DESCRIPTION sFaveLinksProjectionMap[FaveLinksColumns.PHOTO] = FaveLinksColumns.FULL_PHOTO + sFavePostsProjectionMap = HashMap() sFavePostsProjectionMap[BaseColumns._ID] = FavePostsColumns.FULL_ID sFavePostsProjectionMap[FavePostsColumns.POST] = FavePostsColumns.FULL_POST + sCountriesProjectionMap = HashMap() sCountriesProjectionMap[BaseColumns._ID] = CountriesColumns.FULL_ID sCountriesProjectionMap[CountriesColumns.NAME] = CountriesColumns.FULL_NAME + sFeedListsProjectionMap = HashMap() sFeedListsProjectionMap[BaseColumns._ID] = FeedListsColumns.FULL_ID @@ -1174,6 +1266,7 @@ class FenrirContentProvider : ContentProvider() { sFeedListsProjectionMap[FeedListsColumns.NO_REPOSTS] = FeedListsColumns.FULL_NO_REPOSTS sFeedListsProjectionMap[FeedListsColumns.SOURCE_IDS] = FeedListsColumns.FULL_SOURCE_IDS + sFriendListsProjectionMap = HashMap() sFriendListsProjectionMap[BaseColumns._ID] = FriendListsColumns.FULL_ID sFriendListsProjectionMap[FriendListsColumns.USER_ID] = @@ -1181,6 +1274,7 @@ class FenrirContentProvider : ContentProvider() { sFriendListsProjectionMap[FriendListsColumns.LIST_ID] = FriendListsColumns.FULL_LIST_ID sFriendListsProjectionMap[FriendListsColumns.NAME] = FriendListsColumns.FULL_NAME + sKeysProjectionMap = HashMap() sKeysProjectionMap[BaseColumns._ID] = KeyColumns.FULL_ID sKeysProjectionMap[KeyColumns.VERSION] = KeyColumns.FULL_VERSION @@ -1196,6 +1290,8 @@ class FenrirContentProvider : ContentProvider() { sKeysProjectionMap[KeyColumns.OUT_KEY] = KeyColumns.FULL_OUT_KEY sKeysProjectionMap[KeyColumns.IN_KEY] = KeyColumns.FULL_IN_KEY + + //testProjectionMaps() } } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/GroupColumns.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/GroupColumns.kt index feb9ab165..2d87b2636 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/GroupColumns.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/GroupColumns.kt @@ -20,9 +20,7 @@ object GroupColumns : BaseColumns { const val PHOTO_200 = "photo_200" const val CAN_ADD_TOPICS = "can_add_topics" const val TOPICS_ORDER = "topics_order" - const val API_FIELDS = - "name,screen_name,is_closed,verified,members_count,is_admin,admin_level," + - "is_member,member_status,type,photo_50,photo_100,photo_200,menu,ban_info" + const val HAS_UNSEEN_STORIES = "has_unseen_stories" const val FULL_ID = TABLENAME + "." + BaseColumns._ID const val FULL_NAME = "$TABLENAME.$NAME" const val FULL_SCREEN_NAME = "$TABLENAME.$SCREEN_NAME" @@ -40,4 +38,5 @@ object GroupColumns : BaseColumns { const val FULL_CAN_ADD_TOPICS = "$TABLENAME.$CAN_ADD_TOPICS" const val FULL_TOPICS_ORDER = "$TABLENAME.$TOPICS_ORDER" const val FULL_IS_BLACK_LISTED = "$TABLENAME.$IS_BLACK_LISTED" + const val FULL_HAS_UNSEEN_STORIES = "$TABLENAME.$HAS_UNSEEN_STORIES" } \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/RelationshipColumns.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/RelationshipColumns.kt index 8bbd9f355..cb9e2baab 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/RelationshipColumns.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/RelationshipColumns.kt @@ -26,19 +26,20 @@ object RelationshipColumns : BaseColumns { const val FOREIGN_SUBJECT_USER_PHOTO_100 = "subject_user_photo_100" const val FOREIGN_SUBJECT_USER_PHOTO_200 = "subject_user_photo_200" const val FOREIGN_SUBJECT_USER_PHOTO_MAX = "subject_user_photo_max" + const val FOREIGN_SUBJECT_USER_HAS_UNSEEN_STORIES = "subject_user_has_unseen_stories" const val FOREIGN_SUBJECT_USER_LAST_SEEN = "subject_user_last_seen" const val FOREIGN_SUBJECT_USER_PLATFORM = "subject_user_platform" const val FOREIGN_SUBJECT_USER_STATUS = "subject_user_status" const val FOREIGN_SUBJECT_USER_SEX = "subject_user_sex" const val FOREIGN_SUBJECT_USER_IS_FRIEND = "subject_user_is_friend" const val FOREIGN_SUBJECT_USER_FRIEND_STATUS = "subject_user_friend_status" - const val FOREIGN_SUBJECT_WRITE_MESSAGE_STATUS = "subject_write_message_status" - const val FOREIGN_SUBJECT_BDATE = "subject_bdate" - const val FOREIGN_SUBJECT_IS_USER_BLACK_LIST = "subject_is_user_in_black_list" - const val FOREIGN_SUBJECT_IS_BLACK_LISTED = "subject_is_black_listed" - const val FOREIGN_SUBJECT_IS_CAN_ACCESS_CLOSED = "subject_is_can_access_closed" - const val FOREIGN_SUBJECT_IS_VERIFIED = "subject_is_verified" - const val FOREIGN_SUBJECT_MAIDEN_NAME = "subject_maiden_name" + const val FOREIGN_SUBJECT_USER_WRITE_MESSAGE_STATUS = "subject_user_write_message_status" + const val FOREIGN_SUBJECT_USER_BDATE = "subject_user_bdate" + const val FOREIGN_SUBJECT_USER_IS_USER_BLACK_LIST = "subject_user_is_user_in_black_list" + const val FOREIGN_SUBJECT_USER_IS_BLACK_LISTED = "subject_user_is_black_listed" + const val FOREIGN_SUBJECT_USER_IS_CAN_ACCESS_CLOSED = "subject_user_is_can_access_closed" + const val FOREIGN_SUBJECT_USER_IS_VERIFIED = "subject_user_is_verified" + const val FOREIGN_SUBJECT_USER_MAIDEN_NAME = "subject_user_maiden_name" const val FOREIGN_SUBJECT_GROUP_NAME = "subject_group_name" const val FOREIGN_SUBJECT_GROUP_SCREEN_NAME = "subject_group_screen_name" const val FOREIGN_SUBJECT_GROUP_PHOTO_50 = "subject_group_photo_50" @@ -53,6 +54,7 @@ object RelationshipColumns : BaseColumns { const val FOREIGN_SUBJECT_GROUP_MEMBERS_COUNT = "subject_group_members_count" const val FOREIGN_SUBJECT_GROUP_MEMBER_STATUS = "subject_group_member_status" const val FOREIGN_SUBJECT_GROUP_TYPE = "subject_group_type" + const val FOREIGN_SUBJECT_GROUP_HAS_UNSEEN_STORIES = "subject_group_has_unseen_stories" fun getCV(objectId: Int, subjectId: Int, type: Int): ContentValues { val cv = ContentValues() diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/UserColumns.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/UserColumns.kt index c1c2e952e..d1b2d0d49 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/UserColumns.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/column/UserColumns.kt @@ -3,9 +3,6 @@ package dev.ragnarok.fenrir.db.column import android.provider.BaseColumns object UserColumns : BaseColumns { - const val API_FIELDS = - "bdate,blacklisted,blacklisted_by_me,can_access_closed,can_post,can_see_all_posts,can_see_audio,can_write_private_message,domain,first_name,friend_status,is_closed,is_favorite,is_friend,is_subscribed,last_name,last_seen,maiden_name,online,online_app,online_mobile,photo_100,photo_200,photo_50,photo_max_orig,platform,screen_name,sex,status,verified" - /** * The table name of books = "books" */ @@ -35,6 +32,7 @@ object UserColumns : BaseColumns { const val IS_CAN_ACCESS_CLOSED = "is_can_access_closed" const val IS_VERIFIED = "is_verified" const val MAIDEN_NAME = "maiden_name" + const val HAS_UNSEEN_STORIES = "has_unseen_stories" /** * The id of the user, includes tablename prefix @@ -64,4 +62,5 @@ object UserColumns : BaseColumns { const val FULL_IS_VERIFIED = "$TABLENAME.$IS_VERIFIED" const val FULL_MAIDEN_NAME = "$TABLENAME.$MAIDEN_NAME" const val FULL_BDATE = "$TABLENAME.$BDATE" + const val FULL_HAS_UNSEEN_STORIES = "$TABLENAME.$HAS_UNSEEN_STORIES" } \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/impl/OwnersStorage.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/impl/OwnersStorage.kt index 1541cf799..bf07638ab 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/impl/OwnersStorage.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/impl/OwnersStorage.kt @@ -526,6 +526,7 @@ internal class OwnersStorage(context: AppStorages) : AbsStorage(context), IOwner cv.put(GroupColumns.IS_CLOSED, dbo.closed) cv.put(GroupColumns.IS_BLACK_LISTED, dbo.isBlacklisted) cv.put(GroupColumns.IS_VERIFIED, dbo.isVerified) + cv.put(GroupColumns.HAS_UNSEEN_STORIES, dbo.hasUnseenStories) cv.put(GroupColumns.IS_ADMIN, dbo.isAdmin) cv.put(GroupColumns.ADMIN_LEVEL, dbo.adminLevel) cv.put(GroupColumns.IS_MEMBER, dbo.isMember) @@ -562,6 +563,7 @@ internal class OwnersStorage(context: AppStorages) : AbsStorage(context), IOwner cv.put(UserColumns.IS_USER_BLACK_LIST, dbo.blacklisted_by_me) cv.put(UserColumns.IS_BLACK_LISTED, dbo.blacklisted) cv.put(UserColumns.IS_VERIFIED, dbo.isVerified) + cv.put(UserColumns.HAS_UNSEEN_STORIES, dbo.hasUnseenStories) cv.put(UserColumns.IS_CAN_ACCESS_CLOSED, dbo.isCan_access_closed) cv.put(UserColumns.MAIDEN_NAME, dbo.maiden_name) return cv @@ -573,6 +575,7 @@ internal class OwnersStorage(context: AppStorages) : AbsStorage(context), IOwner .setScreenName(cursor.getString(GroupColumns.SCREEN_NAME)) .setClosed(cursor.getInt(GroupColumns.IS_CLOSED)) .setVerified(cursor.getBoolean(GroupColumns.IS_VERIFIED)) + .setHasUnseenStories(cursor.getBoolean(GroupColumns.HAS_UNSEEN_STORIES)) .setBlacklisted(cursor.getBoolean(GroupColumns.IS_BLACK_LISTED)) .setAdmin(cursor.getBoolean(GroupColumns.IS_ADMIN)) .setAdminLevel(cursor.getInt(GroupColumns.ADMIN_LEVEL)) @@ -608,6 +611,7 @@ internal class OwnersStorage(context: AppStorages) : AbsStorage(context), IOwner .setBlacklisted_by_me(cursor.getBoolean(UserColumns.IS_USER_BLACK_LIST)) .setBlacklisted(cursor.getBoolean(UserColumns.IS_BLACK_LISTED)) .setVerified(cursor.getBoolean(UserColumns.IS_VERIFIED)) + .setHasUnseenStories(cursor.getBoolean(UserColumns.HAS_UNSEEN_STORIES)) .setCan_access_closed(cursor.getBoolean(UserColumns.IS_CAN_ACCESS_CLOSED)) .setMaiden_name(cursor.getString(UserColumns.MAIDEN_NAME)) } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/impl/RelativeshipStorage.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/impl/RelativeshipStorage.kt index a0954fc60..ae68277ae 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/impl/RelativeshipStorage.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/impl/RelativeshipStorage.kt @@ -278,6 +278,7 @@ internal class RelativeshipStorage(base: AppStorages) : AbsStorage(base), IRelat .setMemberStatus(cursor.getInt(RelationshipColumns.FOREIGN_SUBJECT_GROUP_MEMBER_STATUS)) .setMembersCount(cursor.getInt(RelationshipColumns.FOREIGN_SUBJECT_GROUP_MEMBERS_COUNT)) .setType(cursor.getInt(RelationshipColumns.FOREIGN_SUBJECT_GROUP_TYPE)) + .setHasUnseenStories(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_GROUP_HAS_UNSEEN_STORIES)) .setPhoto50(cursor.getString(RelationshipColumns.FOREIGN_SUBJECT_GROUP_PHOTO_50)) .setPhoto100(cursor.getString(RelationshipColumns.FOREIGN_SUBJECT_GROUP_PHOTO_100)) .setPhoto200(cursor.getString(RelationshipColumns.FOREIGN_SUBJECT_GROUP_PHOTO_200)) @@ -302,13 +303,14 @@ internal class RelativeshipStorage(base: AppStorages) : AbsStorage(base), IRelat .setSex(cursor.getInt(RelationshipColumns.FOREIGN_SUBJECT_USER_SEX)) .setFriend(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_USER_IS_FRIEND)) .setFriendStatus(cursor.getInt(RelationshipColumns.FOREIGN_SUBJECT_USER_FRIEND_STATUS)) - .setCanWritePrivateMessage(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_WRITE_MESSAGE_STATUS)) - .setBdate(cursor.getString(RelationshipColumns.FOREIGN_SUBJECT_BDATE)) - .setBlacklisted_by_me(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_IS_USER_BLACK_LIST)) - .setBlacklisted(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_IS_BLACK_LISTED)) - .setCan_access_closed(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_IS_CAN_ACCESS_CLOSED)) - .setVerified(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_IS_VERIFIED)) - .setMaiden_name(cursor.getString(RelationshipColumns.FOREIGN_SUBJECT_MAIDEN_NAME)) + .setCanWritePrivateMessage(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_USER_WRITE_MESSAGE_STATUS)) + .setBdate(cursor.getString(RelationshipColumns.FOREIGN_SUBJECT_USER_BDATE)) + .setBlacklisted_by_me(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_USER_IS_USER_BLACK_LIST)) + .setBlacklisted(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_USER_IS_BLACK_LISTED)) + .setCan_access_closed(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_USER_IS_CAN_ACCESS_CLOSED)) + .setVerified(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_USER_IS_VERIFIED)) + .setMaiden_name(cursor.getString(RelationshipColumns.FOREIGN_SUBJECT_USER_MAIDEN_NAME)) + .setHasUnseenStories(cursor.getBoolean(RelationshipColumns.FOREIGN_SUBJECT_USER_HAS_UNSEEN_STORIES)) } } } \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/CommunityEntity.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/CommunityEntity.kt index 9f4ffd0b0..19309565c 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/CommunityEntity.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/CommunityEntity.kt @@ -29,6 +29,13 @@ class CommunityEntity(val id: Int) { private set var isBlacklisted = false private set + var hasUnseenStories = false + private set + + fun setHasUnseenStories(hasUnseenStories: Boolean): CommunityEntity { + this.hasUnseenStories = hasUnseenStories + return this + } fun setName(name: String?): CommunityEntity { this.name = name diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/UserDetailsEntity.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/UserDetailsEntity.kt index ce50f84be..7158d76ba 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/UserDetailsEntity.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/UserDetailsEntity.kt @@ -117,6 +117,8 @@ class UserDetailsEntity { private set var isClosed: Boolean = false private set + var cover: Cover? = null + private set fun setClosed(closed: Boolean): UserDetailsEntity { this.isClosed = closed @@ -143,6 +145,11 @@ class UserDetailsEntity { return this } + fun setCover(cover: Cover?): UserDetailsEntity { + this.cover = cover + return this + } + fun setActivities(activities: String?): UserDetailsEntity { this.activities = activities return this @@ -418,4 +425,41 @@ class UserDetailsEntity { return this } } + + @Keep + @Serializable + class Cover { + var isEnabled = false + private set + var images: ArrayList? = null + private set + + fun setImages(images: ArrayList?): Cover { + this.images = images + return this + } + + fun setEnabled(enabled: Boolean): Cover { + isEnabled = enabled + return this + } + } + + @Keep + @Serializable + class CoverImage { + var url: String? = null + private set + var height = 0 + private set + var width = 0 + private set + + operator fun set(url: String?, height: Int, width: Int): CoverImage { + this.url = url + this.height = height + this.width = width + return this + } + } } \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/UserEntity.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/UserEntity.kt index 7755ff65f..a2c5854de 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/UserEntity.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/db/model/entity/UserEntity.kt @@ -26,6 +26,8 @@ class UserEntity(val id: Int) { private set var bdate: String? = null private set + var hasUnseenStories = false + private set @get:UserPlatform @UserPlatform @@ -57,6 +59,11 @@ class UserEntity(val id: Int) { var isCan_access_closed = false private set + fun setHasUnseenStories(hasUnseenStories: Boolean): UserEntity { + this.hasUnseenStories = hasUnseenStories + return this + } + fun setBdate(bdate: String?): UserEntity { this.bdate = bdate return this diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/dialog/directauth/DirectAuthPresenter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/dialog/directauth/DirectAuthPresenter.kt index 667a88b65..d325eac7c 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/dialog/directauth/DirectAuthPresenter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/dialog/directauth/DirectAuthPresenter.kt @@ -85,15 +85,24 @@ class DirectAuthPresenter(savedInstanceState: Bundle?) : } else { val type = t.validationType val sid = t.sid - if ("2fa_sms".equals(type, ignoreCase = true) || "2fa_libverify".equals( + when { + "2fa_sms".equals(type, ignoreCase = true) || "2fa_libverify".equals( type, ignoreCase = true - ) - ) { - requireSmsCode = true - RedirectUrl = t.validationURL - } else if ("2fa_app".equals(type, ignoreCase = true)) { - requireAppCode = true + ) -> { + requireSmsCode = true + RedirectUrl = t.validationURL + } + "2fa_app".equals(type, ignoreCase = true) -> { + requireAppCode = true + } + else -> { + showError(t) + RedirectUrl = t.validationURL + if (!RedirectUrl.isNullOrEmpty()) { + onValidate() + } + } } if (!sid.isNullOrEmpty()) { appendDisposable(networker.vkAuth() diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/AccountsInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/AccountsInteractor.kt index 3837183fe..fc5711581 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/AccountsInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/AccountsInteractor.kt @@ -1,7 +1,7 @@ package dev.ragnarok.fenrir.domain.impl import android.content.Context -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.api.model.VKApiConversation import dev.ragnarok.fenrir.api.model.VKApiProfileInfo @@ -31,7 +31,7 @@ class AccountsInteractor( override fun getBanned(accountId: Int, count: Int, offset: Int): Single { return networker.vkDefault(accountId) .account() - .getBanned(count, offset, Constants.MAIN_OWNER_FIELDS) + .getBanned(count, offset, Fields.FIELDS_BASE_OWNER) .map { items -> val owners = Dto2Model.transformOwners(items.profiles, items.groups) val result = ArrayList(owners.size) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/BoardInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/BoardInteractor.kt index f5ec5b5e0..55cbac8e3 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/BoardInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/BoardInteractor.kt @@ -1,6 +1,6 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.db.interfaces.IStorages import dev.ragnarok.fenrir.db.model.entity.TopicDboEntity @@ -68,7 +68,7 @@ class BoardInteractor( true, null, null, - Constants.MAIN_OWNER_FIELDS + Fields.FIELDS_BASE_OWNER ) .flatMap { response -> val dtos = listEmptyIfNull(response.items) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/CommentsInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/CommentsInteractor.kt index 93eb2cb19..6c3b5f00b 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/CommentsInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/CommentsInteractor.kt @@ -1,6 +1,6 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.api.model.IAttachmentToken import dev.ragnarok.fenrir.api.model.VKApiComment @@ -8,7 +8,6 @@ import dev.ragnarok.fenrir.api.model.VKApiCommunity import dev.ragnarok.fenrir.api.model.VKApiUser import dev.ragnarok.fenrir.api.model.response.DefaultCommentsResponse import dev.ragnarok.fenrir.db.AttachToType -import dev.ragnarok.fenrir.db.column.GroupColumns import dev.ragnarok.fenrir.db.interfaces.IStorages import dev.ragnarok.fenrir.db.model.entity.CommentEntity import dev.ragnarok.fenrir.db.model.entity.OwnerEntities @@ -126,7 +125,7 @@ class CommentsInteractor( offset: Int ): Single> { return networker.vkDefault(accountId) - .comments()["post", ownerId, postId, offset, 100, "desc", null, null, null, Constants.MAIN_OWNER_FIELDS] + .comments()["post", ownerId, postId, offset, 100, "desc", null, null, null, Fields.FIELDS_BASE_OWNER] .flatMap { response -> val commentDtos = response.main?.comments.orEmpty() @@ -156,7 +155,7 @@ class CommentsInteractor( ): Single { val type = commented.typeForStoredProcedure return networker.vkDefault(accountId) - .comments()[type, commented.sourceOwnerId, commented.sourceId, offset, count, sort, startCommentId, threadComment, commented.accessKey, Constants.MAIN_OWNER_FIELDS] + .comments()[type, commented.sourceOwnerId, commented.sourceId, offset, count, sort, startCommentId, threadComment, commented.accessKey, Fields.FIELDS_BASE_OWNER] .flatMap { response -> val commentDtos = response.main?.comments.orEmpty() @@ -424,7 +423,7 @@ class CommentsInteractor( return ownersRepository.getBaseOwnerInfo(accountId, accountId, IOwnersRepository.MODE_ANY) .flatMap { owner -> networker.vkDefault(accountId) - .groups()[accountId, true, "admin,editor", GroupColumns.API_FIELDS, null, 1000] + .groups()[accountId, true, "admin,editor", Fields.FIELDS_BASE_OWNER, null, 1000] .map { obj -> obj.items.orEmpty() } .map> { val owners: MutableList = ArrayList(it.size + 1) @@ -516,7 +515,7 @@ class CommentsInteractor( 100, "desc", true, - Constants.MAIN_OWNER_FIELDS + Fields.FIELDS_BASE_OWNER ) .map { response -> tempData.append(response, continueToCommentId) @@ -653,7 +652,7 @@ class CommentsInteractor( val ownerId = commented.sourceOwnerId val sourceType = commented.sourceType return networker.vkDefault(accountId) - .comments()[type, commented.sourceOwnerId, commented.sourceId, 0, 1, null, commentId, commentThread, commented.accessKey, Constants.MAIN_OWNER_FIELDS] + .comments()[type, commented.sourceOwnerId, commented.sourceId, 0, 1, null, commentId, commentThread, commented.accessKey, Fields.FIELDS_BASE_OWNER] .flatMap { response -> if (response.main == null || safeCountOf(response.main?.comments) != 1) { throw NotFoundException() diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/CommunitiesInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/CommunitiesInteractor.kt index a536c2dda..23bd6ca49 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/CommunitiesInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/CommunitiesInteractor.kt @@ -1,7 +1,7 @@ package dev.ragnarok.fenrir.domain.impl +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker -import dev.ragnarok.fenrir.db.column.GroupColumns import dev.ragnarok.fenrir.db.interfaces.IStorages import dev.ragnarok.fenrir.domain.ICommunitiesInteractor import dev.ragnarok.fenrir.domain.mappers.Dto2Entity.mapCommunities @@ -28,7 +28,7 @@ class CommunitiesInteractor(private val networker: INetworker, private val store store: Boolean ): Single> { return networker.vkDefault(accountId) - .groups()[userId, true, null, GroupColumns.API_FIELDS, offset, count] + .groups()[userId, true, null, Fields.FIELDS_BASE_GROUP, offset, count] .flatMap { items -> val dtos = listEmptyIfNull( items.items @@ -60,7 +60,7 @@ class CommunitiesInteractor(private val networker: INetworker, private val store .search( q, type, - GroupColumns.API_FIELDS, + Fields.FIELDS_BASE_GROUP, countryId, cityId, futureOnly, diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/FaveInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/FaveInteractor.kt index 13c6ad483..e8a2c4413 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/FaveInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/FaveInteractor.kt @@ -1,6 +1,6 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.api.model.FaveLinkDto import dev.ragnarok.fenrir.api.model.VKApiPost @@ -262,7 +262,7 @@ class FaveInteractor( ): Single> { return networker.vkDefault(accountId) .fave() - .getPages(offset, count, Constants.MAIN_OWNER_FIELDS, if (isUser) "users" else "groups") + .getPages(offset, count, Fields.FIELDS_BASE_OWNER, if (isUser) "users" else "groups") .flatMap { items -> val dtos = listEmptyIfNull( items.items diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/FeedInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/FeedInteractor.kt index eef2833fb..45b8a351a 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/FeedInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/FeedInteractor.kt @@ -1,6 +1,6 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.api.model.VKApiNews import dev.ragnarok.fenrir.db.interfaces.IStorages @@ -78,7 +78,7 @@ class FeedInteractor( when (sourceIds) { "likes" -> networker.vkDefault(accountId) .newsfeed() - .getFeedLikes(maxPhotos, startFrom, count, Constants.MAIN_OWNER_FIELDS) + .getFeedLikes(maxPhotos, startFrom, count, Fields.FIELDS_BASE_OWNER) "recommendation" -> networker.vkDefault(accountId) .newsfeed() .getRecommended( @@ -87,7 +87,7 @@ class FeedInteractor( maxPhotos, startFrom, count, - Constants.MAIN_OWNER_FIELDS + Fields.FIELDS_BASE_OWNER ) else -> networker.vkDefault(accountId) .newsfeed() @@ -100,7 +100,7 @@ class FeedInteractor( null, startFrom, count, - Constants.MAIN_OWNER_FIELDS + Fields.FIELDS_BASE_OWNER ) }.flatMap { response -> val nextFrom = response.nextFrom @@ -148,7 +148,7 @@ class FeedInteractor( "updates_full", "updates_audios" ).contains(sourceIds) - ) null else sourceIds, startFrom, count, Constants.MAIN_OWNER_FIELDS] + ) null else sourceIds, startFrom, count, Fields.FIELDS_BASE_OWNER] .flatMap { response -> val blockAds = Settings.get().other().isAd_block_story_news val needStripRepost = Settings.get().other().isStrip_news_repost @@ -225,7 +225,7 @@ class FeedInteractor( if (startDateOption?.timeUnix == 0L) null else startDateOption?.timeUnix, if (endDateOption?.timeUnix == 0L) null else endDateOption?.timeUnix, startFrom, - Constants.MAIN_OWNER_FIELDS + Fields.FIELDS_BASE_OWNER ) .flatMap { response -> val dtos = listEmptyIfNull(response.items) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/GroupSettingsInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/GroupSettingsInteractor.kt index 6e20f1e44..8ca32d2d4 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/GroupSettingsInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/GroupSettingsInteractor.kt @@ -1,6 +1,6 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.api.model.GroupSettingsDto import dev.ragnarok.fenrir.api.model.GroupSettingsDto.PublicCategory @@ -134,7 +134,7 @@ class GroupSettingsInteractor( val nextFrom = IntNextFrom(startFrom.offset + count) return networker.vkDefault(accountId) .groups() - .getBanned(groupId, startFrom.offset, count, Constants.MAIN_OWNER_FIELDS, null) + .getBanned(groupId, startFrom.offset, count, Fields.FIELDS_BASE_OWNER, null) .map { obj -> obj.items.orEmpty() } .flatMap { items -> val ids = VKOwnIds() @@ -201,7 +201,7 @@ class GroupSettingsInteractor( null, null, null, - Constants.MAIN_OWNER_FIELDS, + Fields.FIELDS_BASE_OWNER, "managers" ) .flatMap { items -> diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/LikesInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/LikesInteractor.kt index 91dd59fa5..60ea940ae 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/LikesInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/LikesInteractor.kt @@ -1,6 +1,6 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.domain.ILikesInteractor import dev.ragnarok.fenrir.domain.mappers.Dto2Model.transformOwner @@ -30,7 +30,7 @@ class LikesInteractor(private val networker: INetworker) : ILikesInteractor { offset, count, null, - Constants.MAIN_OWNER_FIELDS + Fields.FIELDS_BASE_OWNER ) .map { response -> val dtos = listEmptyIfNull(response.owners) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/MessagesRepository.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/MessagesRepository.kt index 2916e2f55..51b3b2761 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/MessagesRepository.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/MessagesRepository.kt @@ -8,6 +8,7 @@ import androidx.annotation.StringRes import dev.ragnarok.fenrir.* import dev.ragnarok.fenrir.Includes.provideApplicationContext import dev.ragnarok.fenrir.Includes.provideMainThreadScheduler +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.api.model.* import dev.ragnarok.fenrir.api.model.local_json.ChatJsonResponse @@ -375,7 +376,7 @@ class MessagesRepository( mode: Mode ): Single { val cached = getCachedConversation(accountId, peerId) - val actual = getActualConversaction(accountId, peerId) + val actual = getActualConversation(accountId, peerId) when (mode) { Mode.ANY -> return cached.flatMap { optional -> if (optional.isEmpty) actual else Single.just( @@ -408,10 +409,10 @@ class MessagesRepository( } } - private fun getActualConversaction(accountId: Int, peerId: Int): Single { + private fun getActualConversation(accountId: Int, peerId: Int): Single { return networker.vkDefault(accountId) .messages() - .getConversations(listOf(peerId), true, Constants.MAIN_OWNER_FIELDS) + .getConversations(listOf(peerId), true, Fields.FIELDS_BASE_OWNER) .flatMap { response -> if (response.items.isNullOrEmpty()) { return@flatMap Single.error(NotFoundException()) @@ -434,7 +435,7 @@ class MessagesRepository( override fun getConversation(accountId: Int, peerId: Int, mode: Mode): Flowable { val cached = getCachedConversation(accountId, peerId) - val actual = getActualConversaction(accountId, peerId) + val actual = getActualConversation(accountId, peerId) return when (mode) { Mode.ANY -> cached .flatMap { optional -> @@ -719,7 +720,7 @@ class MessagesRepository( ): Single> { return networker.vkDefault(accountId) .messages() - .getImportantMessages(offset, count, startMessageId, true, Constants.MAIN_OWNER_FIELDS) + .getImportantMessages(offset, count, startMessageId, true, Fields.FIELDS_BASE_OWNER) .flatMap { response -> val dtos: MutableList = if (response.messages == null) mutableListOf() else listEmptyIfNullMutable( @@ -796,7 +797,7 @@ class MessagesRepository( startMessageId, rev, true, - Constants.MAIN_OWNER_FIELDS + Fields.FIELDS_BASE_OWNER ) .flatMap { response -> val dtos: MutableList = listEmptyIfNullMutable(response.messages) @@ -884,7 +885,7 @@ class MessagesRepository( val dialogsStore = storages.dialogs() return networker.vkDefault(accountId) .messages() - .getDialogs(null, count, startMessageId, true, Constants.MAIN_OWNER_FIELDS) + .getDialogs(null, count, startMessageId, true, Fields.FIELDS_BASE_OWNER) .map { response -> if (startMessageId != null && safeCountOf(response.dialogs) > 0) { // remove first item, because we will have duplicate with previous response @@ -1110,7 +1111,7 @@ class MessagesRepository( ): Single> { return networker.vkDefault(accountId) .messages() - .searchConversations(q, count, 1, Constants.MAIN_OWNER_FIELDS) + .searchConversations(q, count, 1, Fields.FIELDS_BASE_OWNER) .flatMap { chattables -> val conversations: List = listEmptyIfNull(chattables.conversations) @@ -1182,7 +1183,7 @@ class MessagesRepository( override fun getChatUsers(accountId: Int, chatId: Int): Single> { return networker.vkDefault(accountId) .messages() - .getConversationMembers(Peer.fromChatId(chatId), Constants.MAIN_OWNER_FIELDS) + .getConversationMembers(Peer.fromChatId(chatId), Fields.FIELDS_BASE_OWNER) .flatMap { chatDto -> val dtos: List = listEmptyIfNull(chatDto.conversationMembers) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/NewsfeedInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/NewsfeedInteractor.kt index fa1cbf494..28528eeb3 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/NewsfeedInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/NewsfeedInteractor.kt @@ -1,6 +1,6 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.api.model.CommentsDto import dev.ragnarok.fenrir.api.model.response.NewsfeedCommentsResponse.* @@ -73,7 +73,7 @@ class NewsfeedInteractor( .newsfeed() .getComments( count, filter, null, null, null, - 1, startFrom, Constants.MAIN_OWNER_FIELDS + 1, startFrom, Fields.FIELDS_BASE_OWNER ) .flatMap { response -> val owners = transformOwners(response.profiles, response.groups) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/OwnersRepository.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/OwnersRepository.kt index 85e740571..62bbbde41 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/OwnersRepository.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/OwnersRepository.kt @@ -1,16 +1,13 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.api.model.AccessIdPair import dev.ragnarok.fenrir.api.model.VKApiCommunity import dev.ragnarok.fenrir.api.model.VKApiStory -import dev.ragnarok.fenrir.api.model.VKApiUser import dev.ragnarok.fenrir.api.model.longpoll.UserIsOfflineUpdate import dev.ragnarok.fenrir.api.model.longpoll.UserIsOnlineUpdate import dev.ragnarok.fenrir.api.model.response.StoryBlockResponce -import dev.ragnarok.fenrir.db.column.GroupColumns -import dev.ragnarok.fenrir.db.column.UserColumns import dev.ragnarok.fenrir.db.interfaces.IOwnersStorage import dev.ragnarok.fenrir.db.model.UserPatch import dev.ragnarok.fenrir.db.model.entity.CommunityEntity @@ -54,7 +51,6 @@ import dev.ragnarok.fenrir.util.Unixtime.now import dev.ragnarok.fenrir.util.Utils import dev.ragnarok.fenrir.util.Utils.join import dev.ragnarok.fenrir.util.Utils.listEmptyIfNull -import dev.ragnarok.fenrir.util.Utils.stringJoin import dev.ragnarok.fenrir.util.VKOwnIds import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Flowable @@ -193,7 +189,7 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw override fun getStoryById(accountId: Int, stories: List): Single> { return networker.vkDefault(accountId) .users() - .getStoryById(stories, 1, Constants.MAIN_OWNER_FIELDS) + .getStoryById(stories, 1, Fields.FIELDS_BASE_OWNER) .flatMap { story -> val dtos = listEmptyIfNull(story.items) val owners = transformOwners(story.profiles, story.groups) @@ -220,7 +216,7 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw override fun getStory(accountId: Int, owner_id: Int?): Single> { return networker.vkDefault(accountId) .users() - .getStory(owner_id, 1, Constants.MAIN_OWNER_FIELDS) + .getStory(owner_id, 1, Fields.FIELDS_BASE_OWNER) .flatMap { story -> val dtos_multy = listEmptyIfNull(story.items) val dtos: MutableList = ArrayList() @@ -255,7 +251,7 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw override fun searchStory(accountId: Int, q: String?, mentioned_id: Int?): Single> { return networker.vkDefault(accountId) .users() - .searchStory(q, mentioned_id, 1000, 1, Constants.MAIN_OWNER_FIELDS) + .searchStory(q, mentioned_id, 1000, 1, Fields.FIELDS_BASE_OWNER) .flatMap { story -> val dtos_multy = listEmptyIfNull(story.items) val dtos: MutableList = ArrayList() @@ -292,7 +288,7 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw IOwnersRepository.MODE_CACHE -> return getCachedFullData(accountId, userId) IOwnersRepository.MODE_NET -> return networker.vkDefault(accountId) .users() - .getUserWallInfo(userId, VKApiUser.ALL_FIELDS, null) + .getUserWallInfo(userId, Fields.FIELDS_FULL_USER, null) .flatMap { user -> val userEntity = mapUser(user) val detailsEntity = mapUserDetails(user) @@ -375,7 +371,7 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw IOwnersRepository.MODE_CACHE -> return getCachedGroupsFullData(accountId, communityId) IOwnersRepository.MODE_NET -> return networker.vkDefault(accountId) .groups() - .getWallInfo(communityId.toString(), FIELDS_GROUPS_ALL) + .getWallInfo(communityId.toString(), Fields.FIELDS_FULL_GROUP) .flatMap { dto -> val community = mapCommunity(dto) val details = mapCommunityDetails(dto) @@ -398,7 +394,7 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw completable = completable.andThen( networker.vkDefault(accountId) .groups() - .getById(dividedIds.gids, null, null, GroupColumns.API_FIELDS) + .getById(dividedIds.gids, null, null, Fields.FIELDS_BASE_GROUP) .flatMapCompletable { communities: List? -> cache.storeCommunityDbos( accountId, @@ -409,7 +405,7 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw if (dividedIds.uids.nonNullNoEmpty()) { completable = completable.andThen( networker.vkDefault(accountId) - .users()[dividedIds.uids, null, UserColumns.API_FIELDS, null] + .users()[dividedIds.uids, null, Fields.FIELDS_BASE_USER, null] .flatMapCompletable { cache.storeUserDbos( accountId, @@ -444,7 +440,7 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw override fun apply(orig: String): String { return orig } - }), GroupColumns.API_FIELDS, null, 1000] + }), Fields.FIELDS_BASE_GROUP, null, 1000] .map { obj -> listEmptyIfNull(obj.items) } .map { groups -> val owners: MutableList = ArrayList(groups.size) @@ -533,7 +529,7 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw val sortOption = criteria.findOptionByKey(PeopleSearchCriteria.KEY_SORT) val sort = if (sortOption?.value == null) null else sortOption.value?.id - val fields = UserColumns.API_FIELDS + val fields = Fields.FIELDS_BASE_USER val city = criteria.extractDatabaseEntryValueId(PeopleSearchCriteria.KEY_CITY) val country = criteria.extractDatabaseEntryValueId(PeopleSearchCriteria.KEY_COUNTRY) val hometown = criteria.extractTextValueFromOption(PeopleSearchCriteria.KEY_HOMETOWN) @@ -725,29 +721,29 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw if (dbos.size == gids.size) { return@flatMap Single.just(buildCommunitiesFromDbos(dbos)) } - getActualComminitiesAndStore(accountId, gids) + getActualCommunitiesAndStore(accountId, gids) } - IOwnersRepository.MODE_NET -> return getActualComminitiesAndStore(accountId, gids) + IOwnersRepository.MODE_NET -> return getActualCommunitiesAndStore(accountId, gids) } throw IllegalArgumentException("Invalid mode: $mode") } private fun getActualUsersAndStore(accountId: Int, uids: Collection): Single> { return networker.vkDefault(accountId) - .users()[uids, null, UserColumns.API_FIELDS, null] + .users()[uids, null, Fields.FIELDS_BASE_USER, null] .flatMap { dtos -> cache.storeUserDbos(accountId, mapUsers(dtos)) .andThen(Single.just(transformUsers(dtos))) } } - private fun getActualComminitiesAndStore( + private fun getActualCommunitiesAndStore( accountId: Int, gids: List ): Single> { return networker.vkDefault(accountId) .groups() - .getById(gids, null, null, GroupColumns.API_FIELDS) + .getById(gids, null, null, Fields.FIELDS_BASE_GROUP) .flatMap { dtos -> val communityEntities = mapCommunities(dtos) val communities = transformCommunities(dtos) @@ -817,46 +813,6 @@ class OwnersRepository(private val networker: INetworker, private val cache: IOw } companion object { - private val FIELDS_GROUPS_ALL = stringJoin( - ",", - VKApiCommunity.IS_FAVORITE, - VKApiCommunity.IS_SUBSCRIBED, - VKApiCommunity.MAIN_ALBUM_ID, - VKApiCommunity.CAN_UPLOAD_DOC, - VKApiCommunity.CAN_CTARE_TOPIC, - VKApiCommunity.CAN_UPLOAD_VIDEO, - VKApiCommunity.BAN_INFO, - VKApiCommunity.CITY, - VKApiCommunity.COUNTRY, - VKApiCommunity.DESCRIPTION, - VKApiCommunity.WIKI_PAGE, - VKApiCommunity.MEMBERS_COUNT, - VKApiCommunity.COUNTERS, - VKApiCommunity.START_DATE, - VKApiCommunity.FINISH_DATE, - VKApiCommunity.CAN_POST, - VKApiCommunity.CAN_SEE_ALL_POSTS, - VKApiCommunity.STATUS, - VKApiCommunity.CONTACTS, - VKApiCommunity.LINKS, - VKApiCommunity.FIXED_POST, - VKApiCommunity.VERIFIED, - VKApiCommunity.BLACKLISTED, - VKApiCommunity.SITE, - VKApiCommunity.ACTIVITY, - "member_status", - "can_message", - "cover", - "chats_status", - "is_closed", - "is_member", - "type", - "photo_50", - "photo_100", - "photo_200", - "admin_level", - "menu" - ) private val TO_BUNDLE_FUNCTION = BiFunction, List, IOwnersBundle> { users: List, communities: List -> val bundle = SparseArrayOwnersBundle(users.size + communities.size) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/RelationshipInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/RelationshipInteractor.kt index e4ef8b2d8..134726483 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/RelationshipInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/RelationshipInteractor.kt @@ -1,8 +1,7 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker -import dev.ragnarok.fenrir.db.column.UserColumns import dev.ragnarok.fenrir.db.interfaces.IStorages import dev.ragnarok.fenrir.domain.IRelationshipInteractor import dev.ragnarok.fenrir.domain.IRelationshipInteractor.DeletedCodes @@ -46,7 +45,7 @@ class RelationshipInteractor( null, offset, count, - Constants.MAIN_OWNER_FIELDS, + Fields.FIELDS_BASE_OWNER, filter ) .flatMap { items -> @@ -90,7 +89,7 @@ class RelationshipInteractor( ): Single> { val order = if (accountId == objectId) "hints" else null return networker.vkDefault(accountId) - .friends()[objectId, order, null, count, offset, UserColumns.API_FIELDS, null] + .friends()[objectId, order, null, count, offset, Fields.FIELDS_BASE_USER, null] .map { items -> listEmptyIfNull(items.items) } .flatMap { dtos -> val dbos = mapUsers(dtos) @@ -111,7 +110,7 @@ class RelationshipInteractor( if (accountId == objectId) "hints" else null // hints (сортировка по популярности) доступна только для своих друзей return networker.vkDefault(accountId) .friends() - .getOnline(objectId, order, count, offset, UserColumns.API_FIELDS) + .getOnline(objectId, order, count, offset, Fields.FIELDS_BASE_USER) .map { response -> listEmptyIfNull(response.profiles) } .map { obj -> transformUsers(obj) } } @@ -119,7 +118,7 @@ class RelationshipInteractor( override fun getRecommendations(accountId: Int, count: Int?): Single> { return networker.vkDefault(accountId) .friends() - .getRecommendations(count, UserColumns.API_FIELDS, null) + .getRecommendations(count, Fields.FIELDS_BASE_USER, null) .map { response -> listEmptyIfNull(response.items) } .map { obj -> transformUsers(obj) } } @@ -132,7 +131,7 @@ class RelationshipInteractor( ): Single> { return networker.vkDefault(accountId) .users() - .getFollowers(objectId, offset, count, UserColumns.API_FIELDS, null) + .getFollowers(objectId, offset, count, Fields.FIELDS_BASE_USER, null) .map { items -> listEmptyIfNull(items.items) } .flatMap { dtos -> val dbos = mapUsers(dtos) @@ -151,7 +150,7 @@ class RelationshipInteractor( ): Single> { return networker.vkDefault(accountId) .users() - .getRequests(offset, count, 1, 1, UserColumns.API_FIELDS) + .getRequests(offset, count, 1, 1, Fields.FIELDS_BASE_USER) .map { items -> listEmptyIfNull(items.items) } .flatMap { dtos -> val dbos = mapUsers(dtos) @@ -174,7 +173,7 @@ class RelationshipInteractor( ): Single> { return networker.vkDefault(accountId) .friends() - .getMutual(accountId, objectId, count, offset, UserColumns.API_FIELDS) + .getMutual(accountId, objectId, count, offset, Fields.FIELDS_BASE_USER) .map { obj -> transformUsers(obj) } } @@ -187,7 +186,7 @@ class RelationshipInteractor( ): Single, Int>> { return networker.vkDefault(accountId) .friends() - .search(userId, q, UserColumns.API_FIELDS, null, offset, count) + .search(userId, q, Fields.FIELDS_BASE_USER, null, offset, count) .map { items -> val users = transformUsers(listEmptyIfNull(items.items)) create(users, items.count) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/WallsRepository.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/WallsRepository.kt index d1d8679f8..5c7eb3a4d 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/WallsRepository.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/impl/WallsRepository.kt @@ -1,6 +1,6 @@ package dev.ragnarok.fenrir.domain.impl -import dev.ragnarok.fenrir.Constants +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.interfaces.INetworker import dev.ragnarok.fenrir.api.model.IAttachmentToken import dev.ragnarok.fenrir.db.interfaces.IStorages @@ -151,7 +151,7 @@ class WallsRepository( wallFilter: Int ): Single> { return networker.vkDefault(accountId) - .wall()[ownerId, null, offset, count, convertToApiFilter(wallFilter), true, Constants.MAIN_OWNER_FIELDS] + .wall()[ownerId, null, offset, count, convertToApiFilter(wallFilter), true, Fields.FIELDS_BASE_OWNER] .flatMap { response -> val owners = transformOwners(response.profiles, response.groups) val dtos = listEmptyIfNull(response.posts) @@ -182,7 +182,7 @@ class WallsRepository( needStore: Boolean ): Single> { return networker.vkDefault(accountId) - .wall()[ownerId, null, offset, count, convertToApiFilter(wallFilter), true, Constants.MAIN_OWNER_FIELDS] + .wall()[ownerId, null, offset, count, convertToApiFilter(wallFilter), true, Fields.FIELDS_BASE_OWNER] .flatMap { response -> val owners = transformOwners(response.profiles, response.groups) val dtos = listEmptyIfNull(response.posts) @@ -310,7 +310,7 @@ class WallsRepository( val id = dev.ragnarok.fenrir.api.model.IdPair(postId, ownerId) return networker.vkDefault(accountId) .wall() - .getById(setOf(id), true, 5, Constants.MAIN_OWNER_FIELDS) + .getById(setOf(id), true, 5, Fields.FIELDS_BASE_OWNER) .flatMap { response -> if (response.posts.isNullOrEmpty()) { throw NotFoundException() @@ -419,7 +419,7 @@ class WallsRepository( val cache = storages.wall() return networker.vkDefault(accountId) .wall() - .getById(singlePair(postId, ownerId), true, 5, Constants.MAIN_OWNER_FIELDS) + .getById(singlePair(postId, ownerId), true, 5, Fields.FIELDS_BASE_OWNER) .flatMap { response -> if (safeCountOf(response.posts) != 1) { throw NotFoundException() @@ -458,7 +458,7 @@ class WallsRepository( count, offset, true, - Constants.MAIN_OWNER_FIELDS + Fields.FIELDS_BASE_OWNER ) .flatMap { response -> val dtos = listEmptyIfNull(response.items) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Dto2Entity.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Dto2Entity.kt index 7ffeeaedc..caaa2020d 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Dto2Entity.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Dto2Entity.kt @@ -360,6 +360,7 @@ object Dto2Entity { .setPhoto100(community.photo_100) .setPhoto200(community.photo_200) .setMembersCount(community.members_count) + .setHasUnseenStories(community.has_unseen_stories) } @@ -405,6 +406,7 @@ object Dto2Entity { .setVerified(user.verified) .setMaiden_name(user.maiden_name) .setBdate(user.bdate) + .setHasUnseenStories(user.has_unseen_stories) } @@ -553,6 +555,22 @@ object Dto2Entity { dbo.setBooks(user.books) dbo.setFavorite(user.is_favorite) dbo.setSubscribed(user.is_subscribed) + dbo.setCover(user.cover.requireNonNull({ + val cover = UserDetailsEntity.Cover() + .setEnabled(it.enabled) + .setImages(ArrayList(safeCountOf(it.images))) + it.images.requireNonNull { pit -> + for (imageDto in pit) { + cover.images?.add( + UserDetailsEntity.CoverImage() + .set(imageDto.url, imageDto.height, imageDto.width) + ) + } + } + cover + }, { + UserDetailsEntity.Cover().setEnabled(false) + })) return dbo } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Dto2Model.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Dto2Model.kt index c1dde93a8..01bcf99be 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Dto2Model.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Dto2Model.kt @@ -107,6 +107,7 @@ object Dto2Model { .setPhoto100(community.photo_100) .setPhoto200(community.photo_200) .setMembersCount(community.members_count) + .setHasUnseenStories(community.has_unseen_stories) } fun transform(dto: VKApiGiftItem): GiftItem { @@ -217,6 +218,7 @@ object Dto2Model { .setBdate(user.bdate) .setVerified(user.verified) .setMaiden_name(user.maiden_name) + .setHasUnseenStories(user.has_unseen_stories) } fun transform(accountUid: Int, update: AddMessageUpdate): VKApiMessage { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Entity2Model.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Entity2Model.kt index c81e466e7..6f75e9090 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Entity2Model.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/mappers/Entity2Model.kt @@ -74,6 +74,7 @@ object Entity2Model { .setPhoto100(dbo.photo100) .setPhoto200(dbo.photo200) .setMembersCount(dbo.membersCount) + .setHasUnseenStories(dbo.hasUnseenStories) } @@ -232,6 +233,25 @@ object Entity2Model { details.setBooks(dbo.books) details.setFavorite(dbo.isSetFavorite) details.setSubscribed(dbo.isSetSubscribed) + details.setCover(dbo.cover.requireNonNull({ + val cover = UserDetails.Cover() + .setEnabled(it.isEnabled) + .setImages(ArrayList(safeCountOf(it.images))) + it.images.nonNullNoEmpty { pit -> + for (imageDto in pit) { + cover.getImages()?.add( + UserDetails.CoverImage( + imageDto.url, + imageDto.height, + imageDto.width + ) + ) + } + } + cover + }, { + UserDetails.Cover().setEnabled(false) + })) return details } @@ -328,6 +348,7 @@ object Entity2Model { .setCan_access_closed(entity.isCan_access_closed) .setMaiden_name(entity.maiden_name) .setBdate(entity.bdate) + .setHasUnseenStories(entity.hasUnseenStories) } fun map(entity: FavePageEntity): FavePage { @@ -358,6 +379,7 @@ object Entity2Model { .setMemberStatus(entity.memberStatus) .setMembersCount(entity.membersCount) .setCommunityType(entity.type) + .setHasUnseenStories(entity.hasUnseenStories) } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/absownerslist/OwnersAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/absownerslist/OwnersAdapter.kt index e3d588b8c..79ee6f250 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/absownerslist/OwnersAdapter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/absownerslist/OwnersAdapter.kt @@ -27,6 +27,8 @@ import dev.ragnarok.fenrir.util.ViewUtils.getOnlineIcon class OwnersAdapter(private val mContext: Context, private var mData: List) : RecyclerView.Adapter() { private val transformation: Transformation = CurrentTheme.createTransformationForAvatar() + private val transformationWithStory: Transformation = + CurrentTheme.createTransformationStrokeForAvatar() private var mClickListener: ClickListener? = null private var longClickListener: LongClickListener? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { @@ -63,7 +65,7 @@ class OwnersAdapter(private val mContext: Context, private var mData: List) : context, R.layout.item_simple_owner, data ) { private val transformation: Transformation = CurrentTheme.createTransformationForAvatar() + private val transformationWithStory: Transformation = + CurrentTheme.createTransformationStrokeForAvatar() + override fun getCount(): Int { return data.size } @@ -40,7 +43,12 @@ class OwnersListAdapter(context: Activity, private val data: ArrayList) : val holder = view.tag as ViewHolder val item = data[position] holder.tvName.text = item.fullName - displayAvatar(holder.ivAvatar, transformation, item.maxSquareAvatar, Constants.PICASSO_TAG) + displayAvatar( + holder.ivAvatar, + if (item.isHasUnseenStories) transformationWithStory else transformation, + item.maxSquareAvatar, + Constants.PICASSO_TAG + ) holder.subtitle.setText(if (item is User) R.string.profile else R.string.community) return view } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communities/CommunitiesAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communities/CommunitiesAdapter.kt index bf4c47eb1..395fc22c7 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communities/CommunitiesAdapter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communities/CommunitiesAdapter.kt @@ -26,6 +26,8 @@ class CommunitiesAdapter( @StringRes titles: Array ) : MultyDataAdapter(dataWrappers, titles) { private val transformation: Transformation = CurrentTheme.createTransformationForAvatar() + private val transformationWithStory: Transformation = + CurrentTheme.createTransformationStrokeForAvatar() private var actionListener: ActionListener? = null override fun onCreateViewHolder(viewGroup: ViewGroup, position: Int): Holder { return Holder( @@ -44,7 +46,7 @@ class CommunitiesAdapter( } displayAvatar( holder.ivAvatar, - transformation, + if (community.hasUnseenStories) transformationWithStory else transformation, community.maxSquareAvatar, Constants.PICASSO_TAG ) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communitycontrol/communityinfocontacts/CommunityInfoContactsPresenter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communitycontrol/communityinfocontacts/CommunityInfoContactsPresenter.kt index b360150b4..606f5f8b3 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communitycontrol/communityinfocontacts/CommunityInfoContactsPresenter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communitycontrol/communityinfocontacts/CommunityInfoContactsPresenter.kt @@ -4,9 +4,9 @@ import android.os.Bundle import dev.ragnarok.fenrir.Includes.networkInterfaces import dev.ragnarok.fenrir.Includes.provideMainThreadScheduler import dev.ragnarok.fenrir.Includes.stores +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.model.VKApiCommunity import dev.ragnarok.fenrir.api.model.VKApiUser -import dev.ragnarok.fenrir.db.column.UserColumns import dev.ragnarok.fenrir.domain.IGroupSettingsInteractor import dev.ragnarok.fenrir.domain.Repository.owners import dev.ragnarok.fenrir.domain.impl.GroupSettingsInteractor @@ -68,7 +68,7 @@ class CommunityInfoContactsPresenter( val Ids: MutableList = ArrayList(contacts.size) for (it in contacts) Ids.add(it.getUserId()) appendDisposable( - networkInterfaces.vkDefault(accountId).users()[Ids, null, UserColumns.API_FIELDS, null] + networkInterfaces.vkDefault(accountId).users()[Ids, null, Fields.FIELDS_BASE_USER, null] .fromIOToMain() .subscribe({ t: List? -> setLoadingNow(false) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communitycontrol/communitymanagers/CommunityManagersPresenter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communitycontrol/communitymanagers/CommunityManagersPresenter.kt index e290e0a83..57bde51f9 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communitycontrol/communitymanagers/CommunityManagersPresenter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/communitycontrol/communitymanagers/CommunityManagersPresenter.kt @@ -5,9 +5,9 @@ import dev.ragnarok.fenrir.Includes.networkInterfaces import dev.ragnarok.fenrir.Includes.provideMainThreadScheduler import dev.ragnarok.fenrir.Includes.stores import dev.ragnarok.fenrir.R +import dev.ragnarok.fenrir.api.Fields import dev.ragnarok.fenrir.api.model.VKApiCommunity import dev.ragnarok.fenrir.api.model.VKApiUser -import dev.ragnarok.fenrir.db.column.UserColumns import dev.ragnarok.fenrir.domain.IGroupSettingsInteractor import dev.ragnarok.fenrir.domain.Repository.owners import dev.ragnarok.fenrir.domain.impl.GroupSettingsInteractor @@ -65,7 +65,7 @@ class CommunityManagersPresenter(accountId: Int, groupId: Community, savedInstan val Ids: MutableList = ArrayList(contacts.size) for (it in contacts) Ids.add(it.getUserId()) appendDisposable( - networkInterfaces.vkDefault(accountId).users()[Ids, null, UserColumns.API_FIELDS, null] + networkInterfaces.vkDefault(accountId).users()[Ids, null, Fields.FIELDS_BASE_USER, null] .fromIOToMain() .subscribe({ t: List? -> val users = listEmptyIfNull(t) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/fave/favepages/FavePagesAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/fave/favepages/FavePagesAdapter.kt index e0cb7295f..e133a1e30 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/fave/favepages/FavePagesAdapter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/fave/favepages/FavePagesAdapter.kt @@ -34,6 +34,8 @@ import dev.ragnarok.fenrir.view.natives.rlottie.RLottieImageView class FavePagesAdapter(private var data: List, private val context: Context) : RecyclerView.Adapter() { private val transformation: Transformation = CurrentTheme.createTransformationForAvatar() + private val storyTransformation: Transformation = + CurrentTheme.createTransformationStrokeForAvatar() private var recyclerView: RecyclerView? = null private var clickListener: ClickListener? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { @@ -85,7 +87,7 @@ class FavePagesAdapter(private var data: List, private val context: Co val user = favePage.user displayAvatar( holder.avatar, - transformation, + if (user?.hasUnseenStories == true) storyTransformation else transformation, favePage.owner?.maxSquareAvatar, Constants.PICASSO_TAG, monochrome = user?.blacklisted == true @@ -150,7 +152,7 @@ class FavePagesAdapter(private var data: List, private val context: Co val group = favePage.group displayAvatar( holder.avatar, - transformation, + if (group?.hasUnseenStories == true) storyTransformation else transformation, favePage.owner?.maxSquareAvatar, Constants.PICASSO_TAG ) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/friends/allfriends/FriendsRecycleAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/friends/allfriends/FriendsRecycleAdapter.kt index 4f2a27926..8f27c4720 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/friends/allfriends/FriendsRecycleAdapter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/friends/allfriends/FriendsRecycleAdapter.kt @@ -24,6 +24,8 @@ import dev.ragnarok.fenrir.util.ViewUtils.getOnlineIcon class FriendsRecycleAdapter(private var data: List, private val context: Context) : RecyclerView.Adapter() { private val transformation: Transformation = CurrentTheme.createTransformationForAvatar() + private val transformationWithStory: Transformation = + CurrentTheme.createTransformationStrokeForAvatar() private var group = false private var listener: Listener? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { @@ -49,7 +51,12 @@ class FriendsRecycleAdapter(private var data: List, private val conte if (onlineIcon != null) { holder.online.setImageResource(onlineIcon) } - displayAvatar(holder.avatar, transformation, user.maxSquareAvatar, Constants.PICASSO_TAG) + displayAvatar( + holder.avatar, + if (user.hasUnseenStories) transformationWithStory else transformation, + user.maxSquareAvatar, + Constants.PICASSO_TAG + ) holder.itemView.setOnClickListener { listener?.onUserClick(user) } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/groupwall/GroupWallFragment.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/groupwall/GroupWallFragment.kt index 0b27ea4a6..ec513e6a2 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/groupwall/GroupWallFragment.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/groupwall/GroupWallFragment.kt @@ -2,7 +2,9 @@ package dev.ragnarok.fenrir.fragment.groupwall import android.app.Activity import android.content.DialogInterface +import android.graphics.Bitmap import android.graphics.Color +import android.graphics.drawable.Drawable import android.os.Bundle import android.text.method.LinkMovementMethod import android.view.* @@ -17,6 +19,8 @@ import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.textview.MaterialTextView +import com.squareup.picasso3.BitmapTarget +import com.squareup.picasso3.Picasso import dev.ragnarok.fenrir.* import dev.ragnarok.fenrir.activity.ActivityUtils.setToolbarSubtitle import dev.ragnarok.fenrir.activity.ActivityUtils.setToolbarTitle @@ -54,6 +58,7 @@ import dev.ragnarok.fenrir.util.Utils import dev.ragnarok.fenrir.util.Utils.dp import dev.ragnarok.fenrir.util.Utils.getVerifiedColor import dev.ragnarok.fenrir.util.Utils.setBackgroundTint +import dev.ragnarok.fenrir.view.ProfileCoverDrawable import dev.ragnarok.fenrir.view.natives.rlottie.RLottieImageView import kotlin.math.abs @@ -91,9 +96,9 @@ class GroupWallFragment : AbsWallFragment(), url = i.getUrl() } } - displayCommunityCover(community.isBlacklisted, url) + displayCommunityCover(community.isBlacklisted, url, true) }, { - displayCommunityCover(community.isBlacklisted, community.maxSquareAvatar) + displayCommunityCover(community.isBlacklisted, community.maxSquareAvatar, false) }) val statusText: String? = if (details.getStatusAudio() != null) { details.getStatusAudio()?.artistAndTitle @@ -180,7 +185,7 @@ class GroupWallFragment : AbsWallFragment(), mHeaderHolder?.ivAvatar?.let { val sks = with() .load(photoUrl) - .transform(CurrentTheme.createTransformationForAvatar()) + .transform(if (community.hasUnseenStories) CurrentTheme.createTransformationStrokeForAvatar() else CurrentTheme.createTransformationForAvatar()) if (community.isBlacklisted) { sks.transform(MonochromeTransformation()) } @@ -228,18 +233,54 @@ class GroupWallFragment : AbsWallFragment(), LinkHelper.openUrl(requireActivity(), accountId, link, false) } - private fun displayCommunityCover(blacklisted: Boolean, resource: String?) { + private val coverTarget = object : BitmapTarget { + override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) { + if (isAdded) { + mHeaderHolder?.vgCover?.let { + ProfileCoverDrawable.setBitmap( + it, + bitmap, + 0.6f + ) + } + } + } + + override fun onPrepareLoad(placeHolderDrawable: Drawable?) { + } + + override fun onBitmapFailed(e: Exception, errorDrawable: Drawable?) { + if (isAdded) { + mHeaderHolder?.vgCover?.background = null + } + } + } + + private fun displayCommunityCover( + blacklisted: Boolean, + resource: String?, + supportOpen: Boolean + ) { if (!Settings.get().other().isShow_wall_cover) return + if (supportOpen) { + mHeaderHolder?.vgCover?.setOnLongClickListener { + presenter?.fireAvatarPhotoClick(resource, null) + true + } + } else { + mHeaderHolder?.vgCover?.setOnLongClickListener { + false + } + } + with().cancelRequest(coverTarget) if (resource.nonNullNoEmpty()) { - mHeaderHolder?.vgCover?.let { - val sks = with() - .load(resource) - .transform(BlurTransformation(6f, requireActivity())) - if (blacklisted) { - sks.transform(MonochromeTransformation()) - } - sks.into(it) + val sks = with() + .load(resource) + .transform(BlurTransformation(6f, requireActivity())) + if (blacklisted) { + sks.transform(MonochromeTransformation()) } + sks.into(coverTarget) } } @@ -512,7 +553,7 @@ class GroupWallFragment : AbsWallFragment(), private inner class GroupHeaderHolder(root: View) { val blacklisted: RLottieImageView = root.findViewById(R.id.item_blacklisted) - val vgCover: ImageView = root.findViewById(R.id.cover) + val vgCover: ViewGroup = root.findViewById(R.id.cover) val ivAvatar: ImageView = root.findViewById(R.id.header_group_avatar) val ivVerified: ImageView = root.findViewById(R.id.item_verified) val bDonate: RLottieImageView = root.findViewById(R.id.donated_anim) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/search/peoplesearch/PeopleAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/search/peoplesearch/PeopleAdapter.kt index 5c3608cc4..3402acb00 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/search/peoplesearch/PeopleAdapter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/search/peoplesearch/PeopleAdapter.kt @@ -27,6 +27,8 @@ import dev.ragnarok.fenrir.util.ViewUtils.getOnlineIcon class PeopleAdapter(private val mContext: Context, private var mData: List) : RecyclerView.Adapter() { private val transformation: Transformation = CurrentTheme.createTransformationForAvatar() + private val transformationWithStory: Transformation = + CurrentTheme.createTransformationStrokeForAvatar() private var mClickListener: ClickListener? = null private var longClickListener: LongClickListener? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { @@ -63,7 +65,7 @@ class PeopleAdapter(private val mContext: Context, private var mData: List(), IU mHeaderHolder?.ivAvatar?.let { val sks = with() .load(photoUrl) - .transform(CurrentTheme.createTransformationForAvatar()) + .transform(if (user.hasUnseenStories) CurrentTheme.createTransformationStrokeForAvatar() else CurrentTheme.createTransformationForAvatar()) if (user.blacklisted) { sks.transform(MonochromeTransformation()) } sks.into(it) } - if (Settings.get().other().isShow_wall_cover) { - mHeaderHolder?.vgCover?.let { - val sks = with() - .load(photoUrl) - .transform(BlurTransformation(6f, requireActivity())) - if (user.blacklisted) { - sks.transform(MonochromeTransformation()) - } - sks.into(it) - } - } } val donate_anim = Settings.get().other().donate_anim_set if (donate_anim > 0 && user.isDonated) { @@ -261,6 +256,59 @@ class UserWallFragment : AbsWallFragment(), IU mHeaderHolder?.blacklisted?.visibility = if (user.blacklisted) View.VISIBLE else View.GONE } + private val coverTarget = object : BitmapTarget { + override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) { + if (isAdded) { + mHeaderHolder?.vgCover?.let { + ProfileCoverDrawable.setBitmap( + it, + bitmap, + 0.6f + ) + } + } + } + + override fun onPrepareLoad(placeHolderDrawable: Drawable?) { + } + + override fun onBitmapFailed(e: Exception, errorDrawable: Drawable?) { + if (isAdded) { + mHeaderHolder?.vgCover?.background = null + } + } + } + + override fun displayUserCover(blacklisted: Boolean, resource: String?, supportOpen: Boolean) { + if (!Settings.get().other().isShow_wall_cover) return + if (supportOpen) { + mHeaderHolder?.vgCover?.setOnLongClickListener { + val usr = presenter?.user + ?: return@setOnLongClickListener false + getSingleURLPhotoPlace( + resource, + usr.fullName, + "id" + usr.getObjectId() + ).tryOpenWith(requireActivity()) + true + } + } else { + mHeaderHolder?.vgCover?.setOnLongClickListener { + false + } + } + with().cancelRequest(coverTarget) + if (resource.nonNullNoEmpty()) { + val sks = with() + .load(resource) + .transform(BlurTransformation(6f, requireActivity())) + if (blacklisted) { + sks.transform(MonochromeTransformation()) + } + sks.into(coverTarget) + } + } + override fun openUserDetails(accountId: Int, user: User, details: UserDetails) { getUserDetailsPlace(accountId, user, details).tryOpenWith(requireActivity()) } @@ -655,7 +703,7 @@ class UserWallFragment : AbsWallFragment(), IU } private inner class UserHeaderHolder(root: View) { - val vgCover: ImageView = root.findViewById(R.id.cover) + val vgCover: ViewGroup = root.findViewById(R.id.cover) val ivAvatar: ImageView = root.findViewById(R.id.avatar) val ivVerified: ImageView = root.findViewById(R.id.item_verified) val tvName: TextView = root.findViewById(R.id.fragment_user_profile_name) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/userwall/UserWallPresenter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/userwall/UserWallPresenter.kt index 1c7c2a508..dd9bfdaa6 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/userwall/UserWallPresenter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/userwall/UserWallPresenter.kt @@ -184,6 +184,22 @@ class UserWallPresenter( } } + private fun resolveCoverImage() { + details.getCover()?.getImages().ifNonNullNoEmpty({ + var def = 0 + var url: String? = null + for (i in it) { + if (i.getWidth() * i.getHeight() > def) { + def = i.getWidth() * i.getHeight() + url = i.getUrl() + } + } + view?.displayUserCover(user.blacklisted, url, true) + }, { + view?.displayUserCover(user.blacklisted, user.maxSquareAvatar, false) + }) + } + private fun resolveCounters() { view?.displayCounters( details.getFriendsCount(), @@ -242,17 +258,18 @@ class UserWallPresenter( } if (details != null) { this.details = details - onUserDetalsUpdated() + onUserDetailsUpdated() } resolveStatusView() resolveMenu() } - private fun onUserDetalsUpdated() { + private fun onUserDetailsUpdated() { syncFilterCountersWithDetails() view?.notifyWallFiltersChanged() resolvePrimaryActionButton() resolveCounters() + resolveCoverImage() } private fun onUserInfoUpdated() { @@ -288,6 +305,7 @@ class UserWallPresenter( resolveStatusView() resolveMenu() resolveProgressDialogView() + resolveCoverImage() } private fun createPostFilters(): List { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/Community.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/Community.kt index b5b4321cd..5aae8af47 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/Community.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/Community.kt @@ -47,6 +47,8 @@ class Community : Owner { private set var isBlacklisted = false private set + var hasUnseenStories = false + private set constructor(id: Int) : super(OwnerType.COMMUNITY) { this.id = id @@ -68,6 +70,7 @@ class Community : Owner { photo200 = `in`.readString() verified = `in`.getBoolean() isBlacklisted = `in`.getBoolean() + hasUnseenStories = `in`.getBoolean() } internal constructor(`in`: ParcelNative) : super(`in`) { @@ -86,6 +89,7 @@ class Community : Owner { photo200 = `in`.readString() verified = `in`.readBoolean() isBlacklisted = `in`.readBoolean() + hasUnseenStories = `in`.readBoolean() } override val ownerId: Int @@ -108,6 +112,7 @@ class Community : Owner { parcel.writeString(photo200) parcel.putBoolean(verified) parcel.putBoolean(isBlacklisted) + parcel.putBoolean(hasUnseenStories) } override fun writeToParcelNative(dest: ParcelNative) { @@ -127,6 +132,7 @@ class Community : Owner { dest.writeString(photo200) dest.writeBoolean(verified) dest.writeBoolean(isBlacklisted) + dest.writeBoolean(hasUnseenStories) } @AbsModelType @@ -144,6 +150,11 @@ class Community : Owner { return this } + fun setHasUnseenStories(hasUnseenStories: Boolean): Community { + this.hasUnseenStories = hasUnseenStories + return this + } + fun setBlacklisted(isBlacklisted: Boolean): Community { this.isBlacklisted = isBlacklisted return this @@ -220,6 +231,11 @@ class Community : Owner { return verified || isDonated } + override val isHasUnseenStories: Boolean + get() { + return hasUnseenStories + } + fun setVerified(verified: Boolean): Community { this.verified = verified return this diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/Owner.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/Owner.kt index d1a01bdfd..29874d28a 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/Owner.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/Owner.kt @@ -64,6 +64,10 @@ sealed class Owner : AbsModel, ParcelNative.ParcelableNative { get() { throw UnsupportedOperationException() } + open val isHasUnseenStories: Boolean + get() { + throw UnsupportedOperationException() + } companion object { fun readOwnerFromParcel(`in`: Parcel): Owner? { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/User.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/User.kt index ac186d535..f0d190fa6 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/User.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/User.kt @@ -40,6 +40,8 @@ class User : Owner, Identificable { private set var bdate: String? = null private set + var hasUnseenStories = false + private set @UserPlatform var platform = 0 @@ -97,6 +99,7 @@ class User : Owner, Identificable { verified = `in`.getBoolean() isCan_access_closed = `in`.getBoolean() bdate = `in`.readString() + hasUnseenStories = `in`.getBoolean() } internal constructor(`in`: ParcelNative) : super(`in`) { @@ -124,6 +127,7 @@ class User : Owner, Identificable { verified = `in`.readBoolean() isCan_access_closed = `in`.readBoolean() bdate = `in`.readString() + hasUnseenStories = `in`.readBoolean() } @AbsModelType @@ -164,6 +168,11 @@ class User : Owner, Identificable { return this } + fun setHasUnseenStories(hasUnseenStories: Boolean): User { + this.hasUnseenStories = hasUnseenStories + return this + } + fun setPhoto50(photo50: String?): User { this.photo50 = photo50 return this @@ -245,6 +254,11 @@ class User : Owner, Identificable { override val isVerified: Boolean get() = verified || isDonated + override val isHasUnseenStories: Boolean + get() { + return hasUnseenStories + } + fun setVerified(verified: Boolean): User { this.verified = verified return this @@ -281,6 +295,7 @@ class User : Owner, Identificable { parcel.putBoolean(verified) parcel.putBoolean(isCan_access_closed) parcel.writeString(bdate) + parcel.putBoolean(hasUnseenStories) } override fun writeToParcelNative(dest: ParcelNative) { @@ -309,6 +324,7 @@ class User : Owner, Identificable { dest.writeBoolean(verified) dest.writeBoolean(isCan_access_closed) dest.writeString(bdate) + dest.writeBoolean(hasUnseenStories) } override val ownerId: Int diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/UserDetails.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/UserDetails.kt index 312c4376f..28480e7b8 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/UserDetails.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/model/UserDetails.kt @@ -26,7 +26,7 @@ class UserDetails : Parcelable { private var allWallCount = 0 private var ownWallCount = 0 private var postponedWallCount = 0 - private var GiftCount = 0 + private var giftCount = 0 private var productServicesCount = 0 private var narrativesCount = 0 private var city: City? = null @@ -64,30 +64,62 @@ class UserDetails : Parcelable { private var about: String? = null private var books: String? = null private var isClosed: Boolean = false + private var cover: Cover? = null constructor() - internal constructor(`in`: Parcel) { - photoId = `in`.readTypedObjectCompat(IdPair.CREATOR) - statusAudio = `in`.readTypedObjectCompat(Audio.CREATOR) - friendsCount = `in`.readInt() - onlineFriendsCount = `in`.readInt() - mutualFriendsCount = `in`.readInt() - followersCount = `in`.readInt() - groupsCount = `in`.readInt() - photosCount = `in`.readInt() - audiosCount = `in`.readInt() - videosCount = `in`.readInt() - articlesCount = `in`.readInt() - productsCount = `in`.readInt() - productServicesCount = `in`.readInt() - narrativesCount = `in`.readInt() - allWallCount = `in`.readInt() - ownWallCount = `in`.readInt() - postponedWallCount = `in`.readInt() - GiftCount = `in`.readInt() - isFavorite = `in`.getBoolean() - isSubscribed = `in`.getBoolean() - isClosed = `in`.getBoolean() + internal constructor(parcel: Parcel) { + photoId = parcel.readTypedObjectCompat(IdPair.CREATOR) + statusAudio = parcel.readTypedObjectCompat(Audio.CREATOR) + isFavorite = parcel.getBoolean() + isSubscribed = parcel.getBoolean() + friendsCount = parcel.readInt() + onlineFriendsCount = parcel.readInt() + mutualFriendsCount = parcel.readInt() + followersCount = parcel.readInt() + groupsCount = parcel.readInt() + photosCount = parcel.readInt() + audiosCount = parcel.readInt() + articlesCount = parcel.readInt() + productsCount = parcel.readInt() + videosCount = parcel.readInt() + allWallCount = parcel.readInt() + ownWallCount = parcel.readInt() + postponedWallCount = parcel.readInt() + giftCount = parcel.readInt() + productServicesCount = parcel.readInt() + narrativesCount = parcel.readInt() + city = parcel.readTypedObjectCompat(City.CREATOR) + country = parcel.readTypedObjectCompat(Country.CREATOR) + hometown = parcel.readString() + phone = parcel.readString() + homePhone = parcel.readString() + skype = parcel.readString() + instagram = parcel.readString() + twitter = parcel.readString() + facebook = parcel.readString() + relatives = parcel.createTypedArrayList(Relative) + relation = parcel.readInt() + relationPartner = parcel.readTypedObjectCompat(ParcelableOwnerWrapper.CREATOR)!!.get() + languages = parcel.createStringArray() + political = parcel.readInt() + peopleMain = parcel.readInt() + lifeMain = parcel.readInt() + smoking = parcel.readInt() + alcohol = parcel.readInt() + inspiredBy = parcel.readString() + religion = parcel.readString() + site = parcel.readString() + interests = parcel.readString() + music = parcel.readString() + activities = parcel.readString() + movies = parcel.readString() + tv = parcel.readString() + games = parcel.readString() + quotes = parcel.readString() + about = parcel.readString() + books = parcel.readString() + isClosed = parcel.getBoolean() + cover = parcel.readTypedObjectCompat(Cover.CREATOR) } fun setProductServicesCount(productServicesCount: Int): UserDetails { @@ -189,6 +221,15 @@ class UserDetails : Parcelable { return this } + fun getCover(): Cover? { + return cover + } + + fun setCover(cover: Cover?): UserDetails { + this.cover = cover + return this + } + fun getAbout(): String? { return about } @@ -432,34 +473,6 @@ class UserDetails : Parcelable { return this } - override fun describeContents(): Int { - return 0 - } - - override fun writeToParcel(parcel: Parcel, i: Int) { - parcel.writeTypedObjectCompat(photoId, i) - parcel.writeTypedObjectCompat(statusAudio, i) - parcel.writeInt(friendsCount) - parcel.writeInt(onlineFriendsCount) - parcel.writeInt(mutualFriendsCount) - parcel.writeInt(followersCount) - parcel.writeInt(groupsCount) - parcel.writeInt(photosCount) - parcel.writeInt(audiosCount) - parcel.writeInt(videosCount) - parcel.writeInt(articlesCount) - parcel.writeInt(productsCount) - parcel.writeInt(productServicesCount) - parcel.writeInt(narrativesCount) - parcel.writeInt(allWallCount) - parcel.writeInt(ownWallCount) - parcel.writeInt(postponedWallCount) - parcel.writeInt(GiftCount) - parcel.putBoolean(isFavorite) - parcel.putBoolean(isSubscribed) - parcel.putBoolean(isClosed) - } - fun isClosed(): Boolean { return isClosed } @@ -605,18 +618,25 @@ class UserDetails : Parcelable { } fun getGiftCount(): Int { - return GiftCount + return giftCount } - fun setGiftCount(GiftCount: Int): UserDetails { - this.GiftCount = GiftCount + fun setGiftCount(giftCount: Int): UserDetails { + this.giftCount = giftCount return this } - class Relative { + class Relative() : Parcelable { private var user: User? = null private var type: String? = null private var name: String? = null + + constructor(parcel: Parcel) : this() { + user = parcel.readTypedObjectCompat(User.CREATOR) + type = parcel.readString() + name = parcel.readString() + } + fun getName(): String? { return name } @@ -643,6 +663,173 @@ class UserDetails : Parcelable { this.type = type return this } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeTypedObjectCompat(user, flags) + parcel.writeString(type) + parcel.writeString(name) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Relative { + return Relative(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + + class Cover() : Parcelable { + private var enabled = false + private var images: ArrayList? = null + + constructor(parcel: Parcel) : this() { + enabled = parcel.getBoolean() + images = parcel.createTypedArrayList(CoverImage.CREATOR) + } + + fun getImages(): ArrayList? { + return images + } + + fun setImages(images: ArrayList?): Cover { + this.images = images + return this + } + + fun isEnabled(): Boolean { + return enabled + } + + fun setEnabled(enabled: Boolean): Cover { + this.enabled = enabled + return this + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.putBoolean(enabled) + parcel.writeTypedList(images) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): Cover { + return Cover(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + + class CoverImage(private val url: String?, private val height: Int, private val width: Int) : + Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString(), + parcel.readInt(), + parcel.readInt() + ) + + fun getHeight(): Int { + return height + } + + fun getWidth(): Int { + return width + } + + fun getUrl(): String? { + return url + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(url) + parcel.writeInt(height) + parcel.writeInt(width) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): CoverImage { + return CoverImage(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeTypedObjectCompat(photoId, flags) + parcel.writeTypedObjectCompat(statusAudio, flags) + parcel.putBoolean(isFavorite) + parcel.putBoolean(isSubscribed) + parcel.writeInt(friendsCount) + parcel.writeInt(onlineFriendsCount) + parcel.writeInt(mutualFriendsCount) + parcel.writeInt(followersCount) + parcel.writeInt(groupsCount) + parcel.writeInt(photosCount) + parcel.writeInt(audiosCount) + parcel.writeInt(articlesCount) + parcel.writeInt(productsCount) + parcel.writeInt(videosCount) + parcel.writeInt(allWallCount) + parcel.writeInt(ownWallCount) + parcel.writeInt(postponedWallCount) + parcel.writeInt(giftCount) + parcel.writeInt(productServicesCount) + parcel.writeInt(narrativesCount) + parcel.writeTypedObjectCompat(city, flags) + parcel.writeTypedObjectCompat(country, flags) + parcel.writeString(hometown) + parcel.writeString(phone) + parcel.writeString(homePhone) + parcel.writeString(skype) + parcel.writeString(instagram) + parcel.writeString(twitter) + parcel.writeString(facebook) + parcel.writeTypedList(relatives) + parcel.writeInt(relation) + parcel.writeTypedObjectCompat(ParcelableOwnerWrapper(relationPartner), flags) + parcel.writeStringArray(languages) + parcel.writeInt(political) + parcel.writeInt(peopleMain) + parcel.writeInt(lifeMain) + parcel.writeInt(smoking) + parcel.writeInt(alcohol) + parcel.writeString(inspiredBy) + parcel.writeString(religion) + parcel.writeString(site) + parcel.writeString(interests) + parcel.writeString(music) + parcel.writeString(activities) + parcel.writeString(movies) + parcel.writeString(tv) + parcel.writeString(games) + parcel.writeString(quotes) + parcel.writeString(about) + parcel.writeString(books) + parcel.putBoolean(isClosed) + parcel.writeTypedObjectCompat(cover, flags) + } + + override fun describeContents(): Int { + return 0 } companion object CREATOR : Parcelable.Creator { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/BlurTransformation.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/BlurTransformation.kt index ffeaf5a7f..948d9dbff 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/BlurTransformation.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/BlurTransformation.kt @@ -53,6 +53,12 @@ class BlurTransformation( override fun transform(source: RequestHandler.Result.Bitmap): RequestHandler.Result.Bitmap { var src = source.bitmap if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (mRadius <= 0) { + return RequestHandler.Result.Bitmap( + src, source.loadedFrom, + source.exifRotation + ) + } return RequestHandler.Result.Bitmap( BlurTransformationNew.blur(mRadius, src)!!, source.loadedFrom, @@ -76,6 +82,9 @@ class BlurTransformation( override fun localTransform(source: Bitmap?): Bitmap? { var src = source ?: return null if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (mRadius <= 0) { + return src + } return BlurTransformationNew.blur(mRadius, src) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && src.config == Bitmap.Config.HARDWARE) { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/stroke/EllipseStrokeTransformation.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/stroke/EllipseStrokeTransformation.kt new file mode 100644 index 000000000..9f88be5e1 --- /dev/null +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/stroke/EllipseStrokeTransformation.kt @@ -0,0 +1,31 @@ +package dev.ragnarok.fenrir.picasso.transforms.stroke + +import android.graphics.Bitmap +import androidx.annotation.ColorInt +import com.squareup.picasso3.RequestHandler +import com.squareup.picasso3.Transformation +import dev.ragnarok.fenrir.picasso.transforms.stroke.ImageWithStrokeHelper.getEllipseBitmap + +class EllipseStrokeTransformation(@ColorInt private val strokeFirst: Int) : Transformation { + override fun key(): String { + return "$TAG($strokeFirst)" + } + + override fun localTransform(source: Bitmap?): Bitmap? { + return if (source == null) { + null + } else getEllipseBitmap(strokeFirst, source, 0.35f) + } + + override fun transform(source: RequestHandler.Result.Bitmap): RequestHandler.Result.Bitmap { + return RequestHandler.Result.Bitmap( + getEllipseBitmap(strokeFirst, source.bitmap, 0.35f)!!, + source.loadedFrom, + source.exifRotation + ) + } + + companion object { + private val TAG = EllipseStrokeTransformation::class.java.simpleName + } +} \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/stroke/ImageWithStrokeHelper.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/stroke/ImageWithStrokeHelper.kt new file mode 100644 index 000000000..cc6fd83f0 --- /dev/null +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/stroke/ImageWithStrokeHelper.kt @@ -0,0 +1,131 @@ +package dev.ragnarok.fenrir.picasso.transforms.stroke + +import android.graphics.* +import android.os.Build +import androidx.annotation.ColorInt + +object ImageWithStrokeHelper { + fun getRoundedBitmap( + @ColorInt strokeFirst: Int, + workBitmap: Bitmap? + ): Bitmap? { + workBitmap ?: return null + var bitmap = workBitmap + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && bitmap.config == Bitmap.Config.HARDWARE) { + val tmpBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true) + bitmap.recycle() + bitmap = tmpBitmap + if (bitmap == null) { + return null + } + } + val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(output) + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR) + val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG) + paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) + canvas.drawOval(0f, 0f, bitmap.width.toFloat(), bitmap.height.toFloat(), paint) + + paint.style = Paint.Style.STROKE + val pth = (bitmap.width + bitmap.height).toFloat() / 2 + var rdd = 0.066f * pth + paint.strokeWidth = rdd + paint.shader = null + paint.color = Color.TRANSPARENT + paint.alpha = 0 + paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) + canvas.drawOval( + rdd / 2, + rdd / 2, + (bitmap.width - rdd / 2), + (bitmap.height - rdd / 2), + paint + ) + + rdd = 0.040f * pth + paint.strokeWidth = rdd + paint.color = strokeFirst + paint.alpha = 255 + paint.xfermode = null + canvas.drawOval( + rdd / 2, + rdd / 2, + (bitmap.width - rdd / 2), + (bitmap.height - rdd / 2), + paint + ) + + if (bitmap != output) { + bitmap.recycle() + } + return output + } + + fun getEllipseBitmap( + @ColorInt strokeFirst: Int, + workBitmap: Bitmap?, + angle: Float + ): Bitmap? { + workBitmap ?: return null + var bitmap = workBitmap + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && bitmap.config == Bitmap.Config.HARDWARE) { + val tmpBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true) + bitmap.recycle() + bitmap = tmpBitmap + if (bitmap == null) { + return null + } + } + val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(output) + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR) + val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG) + paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) + val pth = (bitmap.width + bitmap.height).toFloat() / 2 + canvas.drawRoundRect( + 0f, + 0f, + bitmap.width.toFloat(), + bitmap.height.toFloat(), + pth * angle, + pth * angle, + paint + ) + paint.style = Paint.Style.STROKE + var rdd = 0.066f * pth + paint.strokeWidth = rdd + paint.shader = null + paint.color = Color.TRANSPARENT + paint.alpha = 0 + paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) + canvas.drawRoundRect( + rdd / 2, + rdd / 2, + (bitmap.width - rdd / 2), + (bitmap.height - rdd / 2), + pth * angle, + pth * angle, + paint + ) + + rdd = 0.040f * pth + paint.strokeWidth = rdd + paint.color = strokeFirst + paint.alpha = 255 + paint.xfermode = null + canvas.drawRoundRect( + rdd / 2, + rdd / 2, + (bitmap.width - rdd / 2), + (bitmap.height - rdd / 2), + pth * angle, + pth * angle, + paint + ) + + if (bitmap != output) { + bitmap.recycle() + } + return output + } +} diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/stroke/RoundStrokeTransformation.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/stroke/RoundStrokeTransformation.kt new file mode 100644 index 000000000..6f5872e48 --- /dev/null +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/picasso/transforms/stroke/RoundStrokeTransformation.kt @@ -0,0 +1,31 @@ +package dev.ragnarok.fenrir.picasso.transforms.stroke + +import android.graphics.Bitmap +import androidx.annotation.ColorInt +import com.squareup.picasso3.RequestHandler +import com.squareup.picasso3.Transformation +import dev.ragnarok.fenrir.picasso.transforms.stroke.ImageWithStrokeHelper.getRoundedBitmap + +class RoundStrokeTransformation(@ColorInt private val strokeFirst: Int) : Transformation { + override fun key(): String { + return "${TAG}($strokeFirst)" + } + + override fun localTransform(source: Bitmap?): Bitmap? { + return if (source == null) { + null + } else getRoundedBitmap(strokeFirst, source) + } + + override fun transform(source: RequestHandler.Result.Bitmap): RequestHandler.Result.Bitmap { + return RequestHandler.Result.Bitmap( + getRoundedBitmap(strokeFirst, source.bitmap)!!, + source.loadedFrom, + source.exifRotation + ) + } + + companion object { + private val TAG = RoundStrokeTransformation::class.java.simpleName + } +} \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/CurrentTheme.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/CurrentTheme.kt index a720e3754..8977c9d08 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/CurrentTheme.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/CurrentTheme.kt @@ -13,6 +13,8 @@ import de.maxr1998.modernpreferences.PreferenceScreen.Companion.getPreferences import dev.ragnarok.fenrir.R import dev.ragnarok.fenrir.picasso.transforms.EllipseTransformation import dev.ragnarok.fenrir.picasso.transforms.RoundTransformation +import dev.ragnarok.fenrir.picasso.transforms.stroke.EllipseStrokeTransformation +import dev.ragnarok.fenrir.picasso.transforms.stroke.RoundStrokeTransformation import dev.ragnarok.fenrir.util.Utils.setColorFilter import dev.ragnarok.fenrir.view.media.PathAnimator import java.io.File @@ -111,6 +113,17 @@ object CurrentTheme { } } + fun createTransformationStrokeForAvatar(): Transformation { + val style = Settings.get() + .ui() + .avatarStyle + return when (style) { + AvatarStyle.OVAL -> EllipseStrokeTransformation(Color.parseColor("#447bba")) + AvatarStyle.CIRCLE -> RoundStrokeTransformation(Color.parseColor("#447bba")) + else -> RoundStrokeTransformation(Color.parseColor("#447bba")) + } + } + @DrawableRes fun createFavoritesAvatar(): Int { val style = Settings.get() diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/ProfileCoverDrawable.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/ProfileCoverDrawable.kt new file mode 100644 index 000000000..2ad9f22b1 --- /dev/null +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/ProfileCoverDrawable.kt @@ -0,0 +1,72 @@ +package dev.ragnarok.fenrir.view + +import android.graphics.* +import android.graphics.drawable.Drawable +import android.view.View +import dev.ragnarok.fenrir.Constants + +class ProfileCoverDrawable(private val bitmap: Bitmap, private val targetAlpha: Float) : + Drawable() { + private val paint = + Paint(Paint.FILTER_BITMAP_FLAG or Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG) + private val rBmp = Rect() + + private fun determineImageScale( + sourceWidth: Int, + sourceHeight: Int, + targetWidth: Int, + targetHeight: Int + ): Double { + val scalex = targetWidth.toDouble() / sourceWidth + val scaley = targetHeight.toDouble() / sourceHeight + return scalex.coerceAtMost(scaley) + } + + private fun printBitmap(canvas: Canvas) { + val pScale = + determineImageScale(bounds.width(), bounds.height(), bitmap.width, bitmap.height) + val px = bounds.width() * pScale + val py = bounds.height() * pScale + rBmp.left = ((bitmap.width - px) / 2).toInt() + rBmp.top = ((bitmap.height - py) / 2).toInt() + rBmp.right = bitmap.width - rBmp.left + rBmp.bottom = bitmap.height - rBmp.top + canvas.drawBitmap(bitmap, rBmp, bounds, paint) + } + + override fun draw(canvas: Canvas) { + try { + paint.alpha = (targetAlpha * 255).toInt() + printBitmap(canvas) + } catch (e: Exception) { + if (Constants.IS_DEBUG) { + e.printStackTrace() + } + } + } + + override fun setAlpha(alpha: Int) { + } + + override fun setColorFilter(colorFilter: ColorFilter?) { + throw UnsupportedOperationException("setColorFilter unsupported!") + } + + @Deprecated( + "Deprecated in Java", + ReplaceWith("PixelFormat.TRANSLUCENT", "android.graphics.PixelFormat") + ) + override fun getOpacity(): Int { + return PixelFormat.TRANSLUCENT + } + + companion object { + // Only accessed from main thread. + private const val FADE_DURATION = 400f //ms + fun setBitmap(target: View, bitmap: Bitmap, targetAlpha: Float) { + val drawable = ProfileCoverDrawable(bitmap, targetAlpha) + drawable.callback = target + target.background = drawable + } + } +} diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/media/AudioPlayerBackgroundDrawable.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/media/AudioPlayerBackgroundDrawable.kt index 7ddd51783..5476a81d7 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/media/AudioPlayerBackgroundDrawable.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/media/AudioPlayerBackgroundDrawable.kt @@ -263,7 +263,7 @@ class AudioPlayerBackgroundDrawable( val pMin = bitmap.height.coerceAtMost(bitmap.width) rBmp.left = (bitmap.width - pMin) / 2 rBmp.top = (bitmap.height - pMin) / 2 - rBmp.right = pMin - rBmp.left - rBmp.bottom = pMin - rBmp.top + rBmp.right = bitmap.width - rBmp.left + rBmp.bottom = bitmap.height - rBmp.top } } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/media/AudioPlayerCoverDrawable.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/media/AudioPlayerCoverDrawable.kt index 1a1629da7..308e45cf5 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/media/AudioPlayerCoverDrawable.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/media/AudioPlayerCoverDrawable.kt @@ -177,7 +177,7 @@ class AudioPlayerCoverDrawable(private val bitmap: Bitmap) : Drawable() { val pMin = bitmap.height.coerceAtMost(bitmap.width) rBmp.left = (bitmap.width - pMin) / 2 rBmp.top = (bitmap.height - pMin) / 2 - rBmp.right = pMin - rBmp.left - rBmp.bottom = pMin - rBmp.top + rBmp.right = bitmap.width - rBmp.left + rBmp.bottom = bitmap.height - rBmp.top } } diff --git a/app_fenrir/src/main/res/layout/header_group.xml b/app_fenrir/src/main/res/layout/header_group.xml index 33ed582d7..5b642c38b 100644 --- a/app_fenrir/src/main/res/layout/header_group.xml +++ b/app_fenrir/src/main/res/layout/header_group.xml @@ -33,15 +33,8 @@ app:cardElevation="0dp" tools:ignore="UnusedAttribute"> - - - - = Build.VERSION_CODES.S) { + if (mRadius <= 0) { + return RequestHandler.Result.Bitmap( + src, source.loadedFrom, + source.exifRotation + ) + } return RequestHandler.Result.Bitmap( BlurTransformationNew.blur(mRadius, src)!!, source.loadedFrom, @@ -76,6 +82,9 @@ class BlurTransformation( override fun localTransform(source: Bitmap?): Bitmap? { var src = source ?: return null if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (mRadius <= 0) { + return src + } return BlurTransformationNew.blur(mRadius, src) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && src.config == Bitmap.Config.HARDWARE) { diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/view/media/AudioPlayerBackgroundDrawable.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/view/media/AudioPlayerBackgroundDrawable.kt index 192bd5177..79c861b0b 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/view/media/AudioPlayerBackgroundDrawable.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/view/media/AudioPlayerBackgroundDrawable.kt @@ -263,7 +263,7 @@ class AudioPlayerBackgroundDrawable( val pMin = bitmap.height.coerceAtMost(bitmap.width) rBmp.left = (bitmap.width - pMin) / 2 rBmp.top = (bitmap.height - pMin) / 2 - rBmp.right = pMin - rBmp.left - rBmp.bottom = pMin - rBmp.top + rBmp.right = bitmap.width - rBmp.left + rBmp.bottom = bitmap.height - rBmp.top } } \ No newline at end of file diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/view/media/AudioPlayerCoverDrawable.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/view/media/AudioPlayerCoverDrawable.kt index 351176767..0513fa7f9 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/view/media/AudioPlayerCoverDrawable.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/view/media/AudioPlayerCoverDrawable.kt @@ -177,7 +177,7 @@ class AudioPlayerCoverDrawable(private val bitmap: Bitmap) : Drawable() { val pMin = bitmap.height.coerceAtMost(bitmap.width) rBmp.left = (bitmap.width - pMin) / 2 rBmp.top = (bitmap.height - pMin) / 2 - rBmp.right = pMin - rBmp.left - rBmp.bottom = pMin - rBmp.top + rBmp.right = bitmap.width - rBmp.left + rBmp.bottom = bitmap.height - rBmp.top } } \ No newline at end of file diff --git a/compiled_native/libfenrir-release.aar b/compiled_native/libfenrir-release.aar index 05f632e03..4a5351e4a 100644 Binary files a/compiled_native/libfenrir-release.aar and b/compiled_native/libfenrir-release.aar differ diff --git a/fenrir_common/src/main/kotlin/dev/ragnarok/fenrir/Common.kt b/fenrir_common/src/main/kotlin/dev/ragnarok/fenrir/Common.kt index 9e549fc41..eb921fc8c 100644 --- a/fenrir_common/src/main/kotlin/dev/ragnarok/fenrir/Common.kt +++ b/fenrir_common/src/main/kotlin/dev/ragnarok/fenrir/Common.kt @@ -96,7 +96,7 @@ object Common { @DrawableRes fun getSnowRes(paganSymbol: Int): Int { - if (paganSymbol == 16) { + if (paganSymbol == 15) { return R.drawable.ic_maple_leaf } return R.drawable.ic_snowflake diff --git a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/convert.h b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/convert.h index ae9b954f5..85b0338f2 100644 --- a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/convert.h +++ b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/convert.h @@ -299,6 +299,23 @@ int I210ToI422(const uint16_t* src_y, int width, int height); +#define H410ToH420 I410ToI420 +LIBYUV_API +int I410ToI420(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_u, + int dst_stride_u, + uint8_t* dst_v, + int dst_stride_v, + int width, + int height); + #define H410ToH444 I410ToI444 LIBYUV_API int I410ToI444(const uint16_t* src_y, diff --git a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/planar_functions.h b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/planar_functions.h index ffe637056..154f2f213 100644 --- a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/planar_functions.h +++ b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/planar_functions.h @@ -392,6 +392,24 @@ int I210Copy(const uint16_t* src_y, int width, int height); +// Copy I410 to I410. +#define I410ToI410 I410Copy +LIBYUV_API +int I410Copy(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint16_t* dst_y, + int dst_stride_y, + uint16_t* dst_u, + int dst_stride_u, + uint16_t* dst_v, + int dst_stride_v, + int width, + int height); + // Copy NV12. Supports inverting. LIBYUV_API int NV12Copy(const uint8_t* src_y, diff --git a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/rotate.h b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/rotate.h index 684ed5e6d..37460c4ac 100644 --- a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/rotate.h +++ b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/rotate.h @@ -85,6 +85,60 @@ int I444Rotate(const uint8_t* src_y, int height, enum RotationMode mode); +// Rotate I010 frame. +LIBYUV_API +int I010Rotate(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint16_t* dst_y, + int dst_stride_y, + uint16_t* dst_u, + int dst_stride_u, + uint16_t* dst_v, + int dst_stride_v, + int width, + int height, + enum RotationMode mode); + +// Rotate I210 frame. +LIBYUV_API +int I210Rotate(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint16_t* dst_y, + int dst_stride_y, + uint16_t* dst_u, + int dst_stride_u, + uint16_t* dst_v, + int dst_stride_v, + int width, + int height, + enum RotationMode mode); + +// Rotate I410 frame. +LIBYUV_API +int I410Rotate(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint16_t* dst_y, + int dst_stride_y, + uint16_t* dst_u, + int dst_stride_u, + uint16_t* dst_v, + int dst_stride_v, + int width, + int height, + enum RotationMode mode); + // Rotate NV12 input and store in I420. LIBYUV_API int NV12ToI420Rotate(const uint8_t* src_y, @@ -156,6 +210,16 @@ void RotatePlane270(const uint8_t* src, int width, int height); +// Rotate a plane by 0, 90, 180, or 270. +LIBYUV_API +int RotatePlane_16(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width, + int height, + enum RotationMode mode); + // Rotations for when U and V are interleaved. // These functions take one UV input pointer and // split the data into two buffers while diff --git a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/rotate_row.h b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/rotate_row.h index aa8528a92..b773f886e 100644 --- a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/rotate_row.h +++ b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/rotate_row.h @@ -215,7 +215,23 @@ void TransposeUVWx16_Any_LSX(const uint8_t* src, uint8_t* dst_b, int dst_stride_b, int width); +void TransposeWxH_16_C(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width, + int height); +void TransposeWx8_16_C(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width); +void TransposeWx1_16_C(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width); #ifdef __cplusplus } // extern "C" } // namespace libyuv diff --git a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/row.h b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/row.h index 45b172b22..c92781266 100644 --- a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/row.h +++ b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/row.h @@ -11,7 +11,8 @@ #ifndef INCLUDE_LIBYUV_ROW_H_ #define INCLUDE_LIBYUV_ROW_H_ -#include // For malloc. +#include // For NULL +#include // For malloc #include "libyuv/basic_types.h" @@ -829,13 +830,21 @@ struct YuvConstants { #define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a)-1))) -#define align_buffer_64(var, size) \ - uint8_t* var##_mem = (uint8_t*)(malloc((size) + 63)); /* NOLINT */ \ - uint8_t* var = (uint8_t*)(((intptr_t)(var##_mem) + 63) & ~63) /* NOLINT */ +#define align_buffer_64(var, size) \ + void* var##_mem = malloc((size) + 63); /* NOLINT */ \ + uint8_t* var = (uint8_t*)(((intptr_t)var##_mem + 63) & ~63) /* NOLINT */ #define free_aligned_buffer_64(var) \ free(var##_mem); \ - var = 0 + var = NULL + +#define align_buffer_64_16(var, size) \ + void* var##_mem = malloc((size)*2 + 63); /* NOLINT */ \ + uint16_t* var = (uint16_t*)(((intptr_t)var##_mem + 63) & ~63) /* NOLINT */ + +#define free_aligned_buffer_64_16(var) \ + free(var##_mem); \ + var = NULL #if defined(__APPLE__) || defined(__x86_64__) || defined(__llvm__) #define OMITFP @@ -1934,6 +1943,8 @@ void MirrorSplitUVRow_C(const uint8_t* src_uv, uint8_t* dst_v, int width); +void MirrorRow_16_C(const uint16_t* src, uint16_t* dst, int width); + void ARGBMirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width); void ARGBMirrorRow_SSE2(const uint8_t* src, uint8_t* dst, int width); void ARGBMirrorRow_NEON(const uint8_t* src_argb, uint8_t* dst_argb, int width); diff --git a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/scale_row.h b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/scale_row.h index 6cb5e1284..356da19dd 100644 --- a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/scale_row.h +++ b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/scale_row.h @@ -214,6 +214,17 @@ void ScalePlaneVertical_16To8(int src_height, int scale, enum FilterMode filtering); +void ScalePlaneDown2_16To8(int src_width, + int src_height, + int dst_width, + int dst_height, + int src_stride, + int dst_stride, + const uint16_t* src_ptr, + uint8_t* dst_ptr, + int scale, + enum FilterMode filtering); + // Simplify the filtering based on scale factors. enum FilterMode ScaleFilterReduce(int src_width, int src_height, @@ -259,6 +270,11 @@ void ScaleRowDown2_16_C(const uint16_t* src_ptr, ptrdiff_t src_stride, uint16_t* dst, int dst_width); +void ScaleRowDown2_16To8_C(const uint16_t* src_ptr, + ptrdiff_t src_stride, + uint8_t* dst, + int dst_width, + int scale); void ScaleRowDown2Linear_C(const uint8_t* src_ptr, ptrdiff_t src_stride, uint8_t* dst, @@ -267,6 +283,11 @@ void ScaleRowDown2Linear_16_C(const uint16_t* src_ptr, ptrdiff_t src_stride, uint16_t* dst, int dst_width); +void ScaleRowDown2Linear_16To8_C(const uint16_t* src_ptr, + ptrdiff_t src_stride, + uint8_t* dst, + int dst_width, + int scale); void ScaleRowDown2Box_C(const uint8_t* src_ptr, ptrdiff_t src_stride, uint8_t* dst, @@ -279,6 +300,11 @@ void ScaleRowDown2Box_16_C(const uint16_t* src_ptr, ptrdiff_t src_stride, uint16_t* dst, int dst_width); +void ScaleRowDown2Box_16To8_C(const uint16_t* src_ptr, + ptrdiff_t src_stride, + uint8_t* dst, + int dst_width, + int scale); void ScaleRowDown4_C(const uint8_t* src_ptr, ptrdiff_t src_stride, uint8_t* dst, diff --git a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/version.h b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/version.h index c72f74616..dfcef8d8f 100644 --- a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/version.h +++ b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/version.h @@ -11,6 +11,6 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 1854 +#define LIBYUV_VERSION 1856 #endif // INCLUDE_LIBYUV_VERSION_H_ diff --git a/libfenrir/src/main/jni/animation/libyuv/source/convert.cc b/libfenrir/src/main/jni/animation/libyuv/source/convert.cc index b62e513a6..d88efce08 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/convert.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/convert.cc @@ -291,6 +291,52 @@ int I210ToI422(const uint16_t* src_y, 0, 10); } +LIBYUV_API +int I410ToI420(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_u, + int dst_stride_u, + uint8_t* dst_v, + int dst_stride_v, + int width, + int height) { + const int depth = 10; + const int scale = 1 << (24 - depth); + + if (width <= 0 || height == 0) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_y = src_y + (height - 1) * src_stride_y; + src_u = src_u + (height - 1) * src_stride_u; + src_v = src_v + (height - 1) * src_stride_v; + src_stride_y = -src_stride_y; + src_stride_u = -src_stride_u; + src_stride_v = -src_stride_v; + } + + { + const int uv_width = SUBSAMPLE(width, 1, 1); + const int uv_height = SUBSAMPLE(height, 1, 1); + + Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width, + height); + ScalePlaneDown2_16To8(width, height, uv_width, uv_height, src_stride_u, + dst_stride_u, src_u, dst_u, scale, kFilterBilinear); + ScalePlaneDown2_16To8(width, height, uv_width, uv_height, src_stride_v, + dst_stride_v, src_v, dst_v, scale, kFilterBilinear); + } + return 0; +} + LIBYUV_API int I410ToI444(const uint16_t* src_y, int src_stride_y, @@ -839,7 +885,7 @@ int I422ToNV21(const uint8_t* src_y, int y; void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v, uint8_t* dst_uv, int width) = MergeUVRow_C; - void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, + void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; int halfwidth = (width + 1) >> 1; diff --git a/libfenrir/src/main/jni/animation/libyuv/source/planar_functions.cc b/libfenrir/src/main/jni/animation/libyuv/source/planar_functions.cc index f43525d57..e08a44f6f 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/planar_functions.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/planar_functions.cc @@ -333,6 +333,45 @@ int I210Copy(const uint16_t* src_y, return 0; } +// Copy I410. +LIBYUV_API +int I410Copy(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint16_t* dst_y, + int dst_stride_y, + uint16_t* dst_u, + int dst_stride_u, + uint16_t* dst_v, + int dst_stride_v, + int width, + int height) { + if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 || + height == 0) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_y = src_y + (height - 1) * src_stride_y; + src_u = src_u + (height - 1) * src_stride_u; + src_v = src_v + (height - 1) * src_stride_v; + src_stride_y = -src_stride_y; + src_stride_u = -src_stride_u; + src_stride_v = -src_stride_v; + } + + if (dst_y) { + CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + } + CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, width, height); + CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, width, height); + return 0; +} + // Copy I400. LIBYUV_API int I400ToI400(const uint8_t* src_y, @@ -3204,7 +3243,7 @@ void SetPlane(uint8_t* dst_y, int height, uint32_t value) { int y; - void (*SetRow)(uint8_t * dst, uint8_t value, int width) = SetRow_C; + void (*SetRow)(uint8_t* dst, uint8_t value, int width) = SetRow_C; if (width <= 0 || height == 0) { return; @@ -3305,7 +3344,7 @@ int ARGBRect(uint8_t* dst_argb, int height, uint32_t value) { int y; - void (*ARGBSetRow)(uint8_t * dst_argb, uint32_t value, int width) = + void (*ARGBSetRow)(uint8_t* dst_argb, uint32_t value, int width) = ARGBSetRow_C; if (!dst_argb || width <= 0 || height == 0 || dst_x < 0 || dst_y < 0) { return -1; @@ -3610,7 +3649,7 @@ int ARGBSepia(uint8_t* dst_argb, int width, int height) { int y; - void (*ARGBSepiaRow)(uint8_t * dst_argb, int width) = ARGBSepiaRow_C; + void (*ARGBSepiaRow)(uint8_t* dst_argb, int width) = ARGBSepiaRow_C; uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) { return -1; @@ -3753,7 +3792,7 @@ int ARGBColorTable(uint8_t* dst_argb, int width, int height) { int y; - void (*ARGBColorTableRow)(uint8_t * dst_argb, const uint8_t* table_argb, + void (*ARGBColorTableRow)(uint8_t* dst_argb, const uint8_t* table_argb, int width) = ARGBColorTableRow_C; uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; if (!dst_argb || !table_argb || width <= 0 || height <= 0 || dst_x < 0 || @@ -3789,7 +3828,7 @@ int RGBColorTable(uint8_t* dst_argb, int width, int height) { int y; - void (*RGBColorTableRow)(uint8_t * dst_argb, const uint8_t* table_argb, + void (*RGBColorTableRow)(uint8_t* dst_argb, const uint8_t* table_argb, int width) = RGBColorTableRow_C; uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; if (!dst_argb || !table_argb || width <= 0 || height <= 0 || dst_x < 0 || @@ -3834,7 +3873,7 @@ int ARGBQuantize(uint8_t* dst_argb, int width, int height) { int y; - void (*ARGBQuantizeRow)(uint8_t * dst_argb, int scale, int interval_size, + void (*ARGBQuantizeRow)(uint8_t* dst_argb, int scale, int interval_size, int interval_offset, int width) = ARGBQuantizeRow_C; uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0 || @@ -4087,7 +4126,7 @@ int InterpolatePlane(const uint8_t* src0, int height, int interpolation) { int y; - void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, + void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; if (!src0 || !src1 || !dst || width <= 0 || height == 0) { @@ -4167,7 +4206,7 @@ int InterpolatePlane_16(const uint16_t* src0, int height, int interpolation) { int y; - void (*InterpolateRow_16)(uint16_t * dst_ptr, const uint16_t* src_ptr, + void (*InterpolateRow_16)(uint16_t* dst_ptr, const uint16_t* src_ptr, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_16_C; if (!src0 || !src1 || !dst || width <= 0 || height == 0) { @@ -5282,7 +5321,7 @@ int UYVYToNV12(const uint8_t* src_uyvy, int halfwidth = (width + 1) >> 1; void (*SplitUVRow)(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v, int width) = SplitUVRow_C; - void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, + void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; diff --git a/libfenrir/src/main/jni/animation/libyuv/source/rotate.cc b/libfenrir/src/main/jni/animation/libyuv/source/rotate.cc index f1e83cbd4..b1b4458e6 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/rotate.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/rotate.cc @@ -138,7 +138,7 @@ void RotatePlane180(const uint8_t* src, int dst_stride, int width, int height) { - // Swap first and last row and mirror the content. Uses a temporary row. + // Swap top and bottom row and mirror the content. Uses a temporary row. align_buffer_64(row, width); const uint8_t* src_bot = src + src_stride * (height - 1); uint8_t* dst_bot = dst + dst_stride * (height - 1); @@ -209,9 +209,9 @@ void RotatePlane180(const uint8_t* src, // Odd height will harmlessly mirror the middle row twice. for (y = 0; y < half_height; ++y) { - CopyRow(src, row, width); // Copy first row into buffer - MirrorRow(src_bot, dst, width); // Mirror last row into first row - MirrorRow(row, dst_bot, width); // Mirror buffer into last row + CopyRow(src, row, width); // Copy top row into buffer + MirrorRow(src_bot, dst, width); // Mirror bottom row into top row + MirrorRow(row, dst_bot, width); // Mirror buffer into bottom row src += src_stride; dst += dst_stride; src_bot -= src_stride; @@ -476,6 +476,120 @@ int RotatePlane(const uint8_t* src, return -1; } +LIBYUV_API +void TransposePlane_16(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width, + int height) { + int i = height; + // Work across the source in 8x8 tiles + while (i >= 8) { + TransposeWx8_16_C(src, src_stride, dst, dst_stride, width); + src += 8 * src_stride; // Go down 8 rows. + dst += 8; // Move over 8 columns. + i -= 8; + } + + if (i > 0) { + TransposeWxH_16_C(src, src_stride, dst, dst_stride, width, i); + } +} + +static void RotatePlane90_16(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width, + int height) { + // Rotate by 90 is a transpose with the source read + // from bottom to top. So set the source pointer to the end + // of the buffer and flip the sign of the source stride. + src += src_stride * (height - 1); + src_stride = -src_stride; + TransposePlane_16(src, src_stride, dst, dst_stride, width, height); +} + +static void RotatePlane270_16(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width, + int height) { + // Rotate by 270 is a transpose with the destination written + // from bottom to top. So set the destination pointer to the end + // of the buffer and flip the sign of the destination stride. + dst += dst_stride * (width - 1); + dst_stride = -dst_stride; + TransposePlane_16(src, src_stride, dst, dst_stride, width, height); +} + +static void RotatePlane180_16(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width, + int height) { + // Swap top and bottom row and mirror the content. Uses a temporary row. + align_buffer_64_16(row, width); + const uint16_t* src_bot = src + src_stride * (height - 1); + uint16_t* dst_bot = dst + dst_stride * (height - 1); + int half_height = (height + 1) >> 1; + int y; + + // Odd height will harmlessly mirror the middle row twice. + for (y = 0; y < half_height; ++y) { + CopyRow_16_C(src, row, width); // Copy top row into buffer + MirrorRow_16_C(src_bot, dst, width); // Mirror bottom row into top row + MirrorRow_16_C(row, dst_bot, width); // Mirror buffer into bottom row + src += src_stride; + dst += dst_stride; + src_bot -= src_stride; + dst_bot -= dst_stride; + } + free_aligned_buffer_64_16(row); +} + +LIBYUV_API +int RotatePlane_16(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width, + int height, + enum RotationMode mode) { + if (!src || width <= 0 || height == 0 || !dst) { + return -1; + } + + // Negative height means invert the image. + if (height < 0) { + height = -height; + src = src + (height - 1) * src_stride; + src_stride = -src_stride; + } + + switch (mode) { + case kRotate0: + // copy frame + CopyPlane_16(src, src_stride, dst, dst_stride, width, height); + return 0; + case kRotate90: + RotatePlane90_16(src, src_stride, dst, dst_stride, width, height); + return 0; + case kRotate270: + RotatePlane270_16(src, src_stride, dst, dst_stride, width, height); + return 0; + case kRotate180: + RotatePlane180_16(src, src_stride, dst, dst_stride, width, height); + return 0; + default: + break; + } + return -1; +} + LIBYUV_API int I420Rotate(const uint8_t* src_y, int src_stride_y, @@ -544,6 +658,8 @@ int I420Rotate(const uint8_t* src_y, return -1; } +// I422 has half width x full height UV planes, so rotate by 90 and 270 +// require scaling to maintain 422 subsampling. LIBYUV_API int I422Rotate(const uint8_t* src_y, int src_stride_y, @@ -579,31 +695,42 @@ int I422Rotate(const uint8_t* src_y, switch (mode) { case kRotate0: - // copy frame + // Copy frame CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height); CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height); return 0; + + // Note on temporary Y plane for UV. + // Rotation of UV first fits within the Y destination plane rows. + // Y plane is width x height + // Y plane rotated is height x width + // UV plane is (width / 2) x height + // UV plane rotated is height x (width / 2) + // UV plane rotated+scaled is (height / 2) x width. + // UV plane rotated is a temporary that fits within the Y plane rotated. + case kRotate90: - // We need to rotate and rescale, we use plane Y as temporal storage. - RotatePlane90(src_u, src_stride_u, dst_y, height, halfwidth, height); - ScalePlane(dst_y, height, height, halfwidth, dst_u, halfheight, + RotatePlane90(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth, + height); + ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_u, dst_stride_u, halfheight, width, kFilterBilinear); - RotatePlane90(src_v, src_stride_v, dst_y, height, halfwidth, height); - ScalePlane(dst_y, height, height, halfwidth, dst_v, halfheight, + RotatePlane90(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth, + height); + ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_v, dst_stride_v, halfheight, width, kFilterLinear); RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height); return 0; case kRotate270: - // We need to rotate and rescale, we use plane Y as temporal storage. - RotatePlane270(src_u, src_stride_u, dst_y, height, halfwidth, height); - ScalePlane(dst_y, height, height, halfwidth, dst_u, halfheight, + RotatePlane270(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth, + height); + ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_u, dst_stride_u, halfheight, width, kFilterBilinear); - RotatePlane270(src_v, src_stride_v, dst_y, height, halfwidth, height); - ScalePlane(dst_y, height, height, halfwidth, dst_v, halfheight, + RotatePlane270(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth, + height); + ScalePlane(dst_y, dst_stride_y, height, halfwidth, dst_v, dst_stride_v, halfheight, width, kFilterLinear); RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height); - return 0; case kRotate180: RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height); @@ -828,6 +955,228 @@ int Android420ToI420Rotate(const uint8_t* src_y, return -1; } +LIBYUV_API +int I010Rotate(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint16_t* dst_y, + int dst_stride_y, + uint16_t* dst_u, + int dst_stride_u, + uint16_t* dst_v, + int dst_stride_v, + int width, + int height, + enum RotationMode mode) { + int halfwidth = (width + 1) >> 1; + int halfheight = (height + 1) >> 1; + if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y || + !dst_u || !dst_v || dst_stride_y < 0) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_y = src_y + (height - 1) * src_stride_y; + src_u = src_u + (height - 1) * src_stride_u; + src_v = src_v + (height - 1) * src_stride_v; + src_stride_y = -src_stride_y; + src_stride_u = -src_stride_u; + src_stride_v = -src_stride_v; + } + + switch (mode) { + case kRotate0: + // copy frame + return I010Copy(src_y, src_stride_y, src_u, src_stride_u, src_v, + src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u, + dst_v, dst_stride_v, width, height); + case kRotate90: + RotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + RotatePlane90_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, + halfheight); + RotatePlane90_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, + halfheight); + return 0; + case kRotate270: + RotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + RotatePlane270_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, + halfheight); + RotatePlane270_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, + halfheight); + return 0; + case kRotate180: + RotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + RotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, + halfheight); + RotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, + halfheight); + return 0; + default: + break; + } + return -1; +} + +// I210 has half width x full height UV planes, so rotate by 90 and 270 +// require scaling to maintain 422 subsampling. +LIBYUV_API +int I210Rotate(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint16_t* dst_y, + int dst_stride_y, + uint16_t* dst_u, + int dst_stride_u, + uint16_t* dst_v, + int dst_stride_v, + int width, + int height, + enum RotationMode mode) { + int halfwidth = (width + 1) >> 1; + int halfheight = (height + 1) >> 1; + if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y || + !dst_u || !dst_v) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_y = src_y + (height - 1) * src_stride_y; + src_u = src_u + (height - 1) * src_stride_u; + src_v = src_v + (height - 1) * src_stride_v; + src_stride_y = -src_stride_y; + src_stride_u = -src_stride_u; + src_stride_v = -src_stride_v; + } + + switch (mode) { + case kRotate0: + // Copy frame + CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height); + CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height); + return 0; + + // Note on temporary Y plane for UV. + // Rotation of UV first fits within the Y destination plane rows. + // Y plane is width x height + // Y plane rotated is height x width + // UV plane is (width / 2) x height + // UV plane rotated is height x (width / 2) + // UV plane rotated+scaled is (height / 2) x width. + // UV plane rotated is a temporary that fits within the Y plane rotated. + + case kRotate90: + RotatePlane90_16(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth, + height); + ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_u, dst_stride_u, + halfheight, width, kFilterBilinear); + RotatePlane90_16(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth, + height); + ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_v, dst_stride_v, + halfheight, width, kFilterLinear); + RotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + return 0; + case kRotate270: + RotatePlane270_16(src_u, src_stride_u, dst_y, dst_stride_y, halfwidth, + height); + ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_u, dst_stride_u, + halfheight, width, kFilterBilinear); + RotatePlane270_16(src_v, src_stride_v, dst_y, dst_stride_y, halfwidth, + height); + ScalePlane_16(dst_y, dst_stride_y, height, halfwidth, dst_v, dst_stride_v, + halfheight, width, kFilterLinear); + RotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + return 0; + case kRotate180: + RotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + RotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, + height); + RotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, + height); + return 0; + default: + break; + } + return -1; +} + +LIBYUV_API +int I410Rotate(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint16_t* dst_y, + int dst_stride_y, + uint16_t* dst_u, + int dst_stride_u, + uint16_t* dst_v, + int dst_stride_v, + int width, + int height, + enum RotationMode mode) { + if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y || + !dst_u || !dst_v || dst_stride_y < 0) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_y = src_y + (height - 1) * src_stride_y; + src_u = src_u + (height - 1) * src_stride_u; + src_v = src_v + (height - 1) * src_stride_v; + src_stride_y = -src_stride_y; + src_stride_u = -src_stride_u; + src_stride_v = -src_stride_v; + } + + switch (mode) { + case kRotate0: + // copy frame + CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, width, height); + CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, width, height); + return 0; + case kRotate90: + RotatePlane90_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + RotatePlane90_16(src_u, src_stride_u, dst_u, dst_stride_u, width, height); + RotatePlane90_16(src_v, src_stride_v, dst_v, dst_stride_v, width, height); + return 0; + case kRotate270: + RotatePlane270_16(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + RotatePlane270_16(src_u, src_stride_u, dst_u, dst_stride_u, width, + height); + RotatePlane270_16(src_v, src_stride_v, dst_v, dst_stride_v, width, + height); + return 0; + case kRotate180: + RotatePlane180_16(src_y, src_stride_y, dst_y, dst_stride_y, width, + height); + RotatePlane180_16(src_u, src_stride_u, dst_u, dst_stride_u, width, + height); + RotatePlane180_16(src_v, src_stride_v, dst_v, dst_stride_v, width, + height); + return 0; + default: + break; + } + return -1; +} + #ifdef __cplusplus } // extern "C" } // namespace libyuv diff --git a/libfenrir/src/main/jni/animation/libyuv/source/rotate_common.cc b/libfenrir/src/main/jni/animation/libyuv/source/rotate_common.cc index ff212adeb..2617c01b2 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/rotate_common.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/rotate_common.cc @@ -94,8 +94,74 @@ void TransposeUVWxH_C(const uint8_t* src, for (i = 0; i < width * 2; i += 2) { int j; for (j = 0; j < height; ++j) { - dst_a[j + ((i >> 1) * dst_stride_a)] = src[i + (j * src_stride)]; - dst_b[j + ((i >> 1) * dst_stride_b)] = src[i + (j * src_stride) + 1]; + dst_a[((i >> 1) * dst_stride_a) + j] = src[i + (j * src_stride)]; + dst_b[((i >> 1) * dst_stride_b) + j] = src[i + (j * src_stride) + 1]; + } + } +} + +void TransposeWx8_16_C(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width) { + int i; + for (i = 0; i < width; ++i) { + dst[0] = src[0 * src_stride]; + dst[1] = src[1 * src_stride]; + dst[2] = src[2 * src_stride]; + dst[3] = src[3 * src_stride]; + dst[4] = src[4 * src_stride]; + dst[5] = src[5 * src_stride]; + dst[6] = src[6 * src_stride]; + dst[7] = src[7 * src_stride]; + ++src; + dst += dst_stride; + } +} + +void TransposeUVWx8_16_C(const uint16_t* src, + int src_stride, + uint16_t* dst_a, + int dst_stride_a, + uint16_t* dst_b, + int dst_stride_b, + int width) { + int i; + for (i = 0; i < width; ++i) { + dst_a[0] = src[0 * src_stride + 0]; + dst_b[0] = src[0 * src_stride + 1]; + dst_a[1] = src[1 * src_stride + 0]; + dst_b[1] = src[1 * src_stride + 1]; + dst_a[2] = src[2 * src_stride + 0]; + dst_b[2] = src[2 * src_stride + 1]; + dst_a[3] = src[3 * src_stride + 0]; + dst_b[3] = src[3 * src_stride + 1]; + dst_a[4] = src[4 * src_stride + 0]; + dst_b[4] = src[4 * src_stride + 1]; + dst_a[5] = src[5 * src_stride + 0]; + dst_b[5] = src[5 * src_stride + 1]; + dst_a[6] = src[6 * src_stride + 0]; + dst_b[6] = src[6 * src_stride + 1]; + dst_a[7] = src[7 * src_stride + 0]; + dst_b[7] = src[7 * src_stride + 1]; + src += 2; + dst_a += dst_stride_a; + dst_b += dst_stride_b; + } +} + +void TransposeWxH_16_C(const uint16_t* src, + int src_stride, + uint16_t* dst, + int dst_stride, + int width, + int height) { + int i; + for (i = 0; i < width; ++i) { + int j; + for (j = 0; j < height; ++j) { + dst[i * dst_stride + j] = src[j * src_stride + i]; } } } diff --git a/libfenrir/src/main/jni/animation/libyuv/source/row_common.cc b/libfenrir/src/main/jni/animation/libyuv/source/row_common.cc index 3d1e705e5..84afd35ba 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/row_common.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/row_common.cc @@ -2688,6 +2688,19 @@ void MirrorRow_C(const uint8_t* src, uint8_t* dst, int width) { } } +void MirrorRow_16_C(const uint16_t* src, uint16_t* dst, int width) { + int x; + src += width - 1; + for (x = 0; x < width - 1; x += 2) { + dst[x] = src[0]; + dst[x + 1] = src[-1]; + src -= 2; + } + if (width & 1) { + dst[width - 1] = src[0]; + } +} + void MirrorUVRow_C(const uint8_t* src_uv, uint8_t* dst_uv, int width) { int x; src_uv += (width - 1) << 1; diff --git a/libfenrir/src/main/jni/animation/libyuv/source/scale.cc b/libfenrir/src/main/jni/animation/libyuv/source/scale.cc index 2a7e308dc..8c4536e20 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/scale.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/scale.cc @@ -198,6 +198,42 @@ static void ScalePlaneDown2_16(int src_width, } } +void ScalePlaneDown2_16To8(int src_width, + int src_height, + int dst_width, + int dst_height, + int src_stride, + int dst_stride, + const uint16_t* src_ptr, + uint8_t* dst_ptr, + int scale, + enum FilterMode filtering) { + int y; + void (*ScaleRowDown2)(const uint16_t* src_ptr, ptrdiff_t src_stride, + uint8_t* dst_ptr, int dst_width, int scale) = + filtering == kFilterNone + ? ScaleRowDown2_16To8_C + : (filtering == kFilterLinear ? ScaleRowDown2Linear_16To8_C + : ScaleRowDown2Box_16To8_C); + int row_stride = src_stride * 2; + (void)src_width; + (void)src_height; + if (!filtering) { + src_ptr += src_stride; // Point to odd rows. + src_stride = 0; + } + + if (filtering == kFilterLinear) { + src_stride = 0; + } + // TODO(fbarchard): Loop through source height to allow odd height. + for (y = 0; y < dst_height; ++y) { + ScaleRowDown2(src_ptr, src_stride, dst_ptr, dst_width, scale); + src_ptr += row_stride; + dst_ptr += dst_stride; + } +} + // Scale plane, 1/4 // This is an optimized version for scaling down a plane to 1/4 of // its original size. @@ -1020,10 +1056,10 @@ void ScalePlaneBilinearDown(int src_width, const int max_y = (src_height - 1) << 16; int j; - void (*ScaleFilterCols)(uint8_t * dst_ptr, const uint8_t* src_ptr, + void (*ScaleFilterCols)(uint8_t* dst_ptr, const uint8_t* src_ptr, int dst_width, int x, int dx) = (src_width >= 32768) ? ScaleFilterCols64_C : ScaleFilterCols_C; - void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, + void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, @@ -1143,10 +1179,10 @@ void ScalePlaneBilinearDown_16(int src_width, const int max_y = (src_height - 1) << 16; int j; - void (*ScaleFilterCols)(uint16_t * dst_ptr, const uint16_t* src_ptr, + void (*ScaleFilterCols)(uint16_t* dst_ptr, const uint16_t* src_ptr, int dst_width, int x, int dx) = (src_width >= 32768) ? ScaleFilterCols64_16_C : ScaleFilterCols_16_C; - void (*InterpolateRow)(uint16_t * dst_ptr, const uint16_t* src_ptr, + void (*InterpolateRow)(uint16_t* dst_ptr, const uint16_t* src_ptr, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_16_C; ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, @@ -1231,10 +1267,10 @@ void ScalePlaneBilinearUp(int src_width, int dx = 0; int dy = 0; const int max_y = (src_height - 1) << 16; - void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, + void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; - void (*ScaleFilterCols)(uint8_t * dst_ptr, const uint8_t* src_ptr, + void (*ScaleFilterCols)(uint8_t* dst_ptr, const uint8_t* src_ptr, int dst_width, int x, int dx) = filtering ? ScaleFilterCols_C : ScaleCols_C; ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, @@ -1699,10 +1735,10 @@ void ScalePlaneBilinearUp_16(int src_width, int dx = 0; int dy = 0; const int max_y = (src_height - 1) << 16; - void (*InterpolateRow)(uint16_t * dst_ptr, const uint16_t* src_ptr, + void (*InterpolateRow)(uint16_t* dst_ptr, const uint16_t* src_ptr, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_16_C; - void (*ScaleFilterCols)(uint16_t * dst_ptr, const uint16_t* src_ptr, + void (*ScaleFilterCols)(uint16_t* dst_ptr, const uint16_t* src_ptr, int dst_width, int x, int dx) = filtering ? ScaleFilterCols_16_C : ScaleCols_16_C; ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, @@ -1827,7 +1863,7 @@ static void ScalePlaneSimple(int src_width, const uint8_t* src_ptr, uint8_t* dst_ptr) { int i; - void (*ScaleCols)(uint8_t * dst_ptr, const uint8_t* src_ptr, int dst_width, + void (*ScaleCols)(uint8_t* dst_ptr, const uint8_t* src_ptr, int dst_width, int x, int dx) = ScaleCols_C; // Initial source x/y coordinate and step values as 16.16 fixed point. int x = 0; @@ -1864,7 +1900,7 @@ static void ScalePlaneSimple_16(int src_width, const uint16_t* src_ptr, uint16_t* dst_ptr) { int i; - void (*ScaleCols)(uint16_t * dst_ptr, const uint16_t* src_ptr, int dst_width, + void (*ScaleCols)(uint16_t* dst_ptr, const uint16_t* src_ptr, int dst_width, int x, int dx) = ScaleCols_16_C; // Initial source x/y coordinate and step values as 16.16 fixed point. int x = 0; diff --git a/libfenrir/src/main/jni/animation/libyuv/source/scale_argb.cc b/libfenrir/src/main/jni/animation/libyuv/source/scale_argb.cc index 48c108966..3e6f54776 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/scale_argb.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/scale_argb.cc @@ -289,10 +289,10 @@ static void ScaleARGBBilinearDown(int src_width, int dy, enum FilterMode filtering) { int j; - void (*InterpolateRow)(uint8_t * dst_argb, const uint8_t* src_argb, + void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; - void (*ScaleARGBFilterCols)(uint8_t * dst_argb, const uint8_t* src_argb, + void (*ScaleARGBFilterCols)(uint8_t* dst_argb, const uint8_t* src_argb, int dst_width, int x, int dx) = (src_width >= 32768) ? ScaleARGBFilterCols64_C : ScaleARGBFilterCols_C; int64_t xlast = x + (int64_t)(dst_width - 1) * dx; @@ -421,10 +421,10 @@ static void ScaleARGBBilinearUp(int src_width, int dy, enum FilterMode filtering) { int j; - void (*InterpolateRow)(uint8_t * dst_argb, const uint8_t* src_argb, + void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; - void (*ScaleARGBFilterCols)(uint8_t * dst_argb, const uint8_t* src_argb, + void (*ScaleARGBFilterCols)(uint8_t* dst_argb, const uint8_t* src_argb, int dst_width, int x, int dx) = filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C; const int max_y = (src_height - 1) << 16; @@ -668,7 +668,7 @@ static void ScaleYUVToARGBBilinearUp(int src_width, } #endif - void (*InterpolateRow)(uint8_t * dst_argb, const uint8_t* src_argb, + void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; #if defined(HAS_INTERPOLATEROW_SSSE3) @@ -712,7 +712,7 @@ static void ScaleYUVToARGBBilinearUp(int src_width, } #endif - void (*ScaleARGBFilterCols)(uint8_t * dst_argb, const uint8_t* src_argb, + void (*ScaleARGBFilterCols)(uint8_t* dst_argb, const uint8_t* src_argb, int dst_width, int x, int dx) = filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C; if (src_width >= 32768) { @@ -883,7 +883,7 @@ static void ScaleARGBSimple(int src_width, int y, int dy) { int j; - void (*ScaleARGBCols)(uint8_t * dst_argb, const uint8_t* src_argb, + void (*ScaleARGBCols)(uint8_t* dst_argb, const uint8_t* src_argb, int dst_width, int x, int dx) = (src_width >= 32768) ? ScaleARGBCols64_C : ScaleARGBCols_C; (void)src_height; diff --git a/libfenrir/src/main/jni/animation/libyuv/source/scale_common.cc b/libfenrir/src/main/jni/animation/libyuv/source/scale_common.cc index b02bdafd5..55749a2e2 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/scale_common.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/scale_common.cc @@ -23,6 +23,25 @@ namespace libyuv { extern "C" { #endif +#ifdef __cplusplus +#define STATIC_CAST(type, expr) static_cast(expr) +#else +#define STATIC_CAST(type, expr) (type)(expr) +#endif + +// TODO(fbarchard): make clamp255 preserve negative values. +static __inline int32_t clamp255(int32_t v) { + return (-(v >= 255) | v) & 255; +} + +// Use scale to convert lsb formats to msb, depending how many bits there are: +// 32768 = 9 bits +// 16384 = 10 bits +// 4096 = 12 bits +// 256 = 16 bits +// TODO(fbarchard): change scale to bits +#define C16TO8(v, scale) clamp255(((v) * (scale)) >> 16) + static __inline int Abs(int v) { return v >= 0 ? v : -v; } @@ -62,6 +81,26 @@ void ScaleRowDown2_16_C(const uint16_t* src_ptr, } } +void ScaleRowDown2_16To8_C(const uint16_t* src_ptr, + ptrdiff_t src_stride, + uint8_t* dst, + int dst_width, + int scale) { + int x; + (void)src_stride; + assert(scale >= 256); + assert(scale <= 32768); + for (x = 0; x < dst_width - 1; x += 2) { + dst[0] = STATIC_CAST(uint8_t, C16TO8(src_ptr[1], scale)); + dst[1] = STATIC_CAST(uint8_t, C16TO8(src_ptr[3], scale)); + dst += 2; + src_ptr += 4; + } + if (dst_width & 1) { + dst[0] = STATIC_CAST(uint8_t, C16TO8(src_ptr[1], scale)); + } +} + void ScaleRowDown2Linear_C(const uint8_t* src_ptr, ptrdiff_t src_stride, uint8_t* dst, @@ -98,6 +137,27 @@ void ScaleRowDown2Linear_16_C(const uint16_t* src_ptr, } } +void ScaleRowDown2Linear_16To8_C(const uint16_t* src_ptr, + ptrdiff_t src_stride, + uint8_t* dst, + int dst_width, + int scale) { + const uint16_t* s = src_ptr; + int x; + (void)src_stride; + assert(scale >= 256); + assert(scale <= 32768); + for (x = 0; x < dst_width - 1; x += 2) { + dst[0] = STATIC_CAST(uint8_t, C16TO8((s[0] + s[1] + 1) >> 1, scale)); + dst[1] = STATIC_CAST(uint8_t, C16TO8((s[2] + s[3] + 1) >> 1, scale)); + dst += 2; + s += 4; + } + if (dst_width & 1) { + dst[0] = STATIC_CAST(uint8_t, C16TO8((s[0] + s[1] + 1) >> 1, scale)); + } +} + void ScaleRowDown2Box_C(const uint8_t* src_ptr, ptrdiff_t src_stride, uint8_t* dst, @@ -160,6 +220,31 @@ void ScaleRowDown2Box_16_C(const uint16_t* src_ptr, } } +void ScaleRowDown2Box_16To8_C(const uint16_t* src_ptr, + ptrdiff_t src_stride, + uint8_t* dst, + int dst_width, + int scale) { + const uint16_t* s = src_ptr; + const uint16_t* t = src_ptr + src_stride; + int x; + assert(scale >= 256); + assert(scale <= 32768); + for (x = 0; x < dst_width - 1; x += 2) { + dst[0] = STATIC_CAST(uint8_t, + C16TO8((s[0] + s[1] + t[0] + t[1] + 2) >> 2, scale)); + dst[1] = STATIC_CAST(uint8_t, + C16TO8((s[2] + s[3] + t[2] + t[3] + 2) >> 2, scale)); + dst += 2; + s += 4; + t += 4; + } + if (dst_width & 1) { + dst[0] = STATIC_CAST(uint8_t, + C16TO8((s[0] + s[1] + t[0] + t[1] + 2) >> 2, scale)); + } +} + void ScaleRowDown4_C(const uint8_t* src_ptr, ptrdiff_t src_stride, uint8_t* dst, @@ -1469,7 +1554,7 @@ void ScalePlaneVertical(int src_height, enum FilterMode filtering) { // TODO(fbarchard): Allow higher bpp. int dst_width_bytes = dst_width * bpp; - void (*InterpolateRow)(uint8_t * dst_argb, const uint8_t* src_argb, + void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0; @@ -1548,7 +1633,7 @@ void ScalePlaneVertical_16(int src_height, enum FilterMode filtering) { // TODO(fbarchard): Allow higher wpp. int dst_width_words = dst_width * wpp; - void (*InterpolateRow)(uint16_t * dst_argb, const uint16_t* src_argb, + void (*InterpolateRow)(uint16_t* dst_argb, const uint16_t* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_16_C; const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0; @@ -1627,7 +1712,7 @@ void ScalePlaneVertical_16To8(int src_height, // TODO(fbarchard): Allow higher wpp. int dst_width_words = dst_width * wpp; // TODO(https://crbug.com/libyuv/931): Add NEON 32 bit and AVX2 versions. - void (*InterpolateRow_16To8)(uint8_t * dst_argb, const uint16_t* src_argb, + void (*InterpolateRow_16To8)(uint8_t* dst_argb, const uint16_t* src_argb, ptrdiff_t src_stride, int scale, int dst_width, int source_y_fraction) = InterpolateRow_16To8_C; const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0; diff --git a/libfenrir/src/main/jni/animation/libyuv/source/scale_uv.cc b/libfenrir/src/main/jni/animation/libyuv/source/scale_uv.cc index ecda769ee..5b92d0432 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/scale_uv.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/scale_uv.cc @@ -338,10 +338,10 @@ static void ScaleUVBilinearDown(int src_width, int dy, enum FilterMode filtering) { int j; - void (*InterpolateRow)(uint8_t * dst_uv, const uint8_t* src_uv, + void (*InterpolateRow)(uint8_t* dst_uv, const uint8_t* src_uv, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; - void (*ScaleUVFilterCols)(uint8_t * dst_uv, const uint8_t* src_uv, + void (*ScaleUVFilterCols)(uint8_t* dst_uv, const uint8_t* src_uv, int dst_width, int x, int dx) = (src_width >= 32768) ? ScaleUVFilterCols64_C : ScaleUVFilterCols_C; int64_t xlast = x + (int64_t)(dst_width - 1) * dx; @@ -464,10 +464,10 @@ static void ScaleUVBilinearUp(int src_width, int dy, enum FilterMode filtering) { int j; - void (*InterpolateRow)(uint8_t * dst_uv, const uint8_t* src_uv, + void (*InterpolateRow)(uint8_t* dst_uv, const uint8_t* src_uv, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; - void (*ScaleUVFilterCols)(uint8_t * dst_uv, const uint8_t* src_uv, + void (*ScaleUVFilterCols)(uint8_t* dst_uv, const uint8_t* src_uv, int dst_width, int x, int dx) = filtering ? ScaleUVFilterCols_C : ScaleUVCols_C; const int max_y = (src_height - 1) << 16; @@ -854,7 +854,7 @@ static void ScaleUVSimple(int src_width, int y, int dy) { int j; - void (*ScaleUVCols)(uint8_t * dst_uv, const uint8_t* src_uv, int dst_width, + void (*ScaleUVCols)(uint8_t* dst_uv, const uint8_t* src_uv, int dst_width, int x, int dx) = (src_width >= 32768) ? ScaleUVCols64_C : ScaleUVCols_C; (void)src_height; diff --git a/libfenrir/src/main/jni/compress/zstd/compress/huf_compress.c b/libfenrir/src/main/jni/compress/zstd/compress/huf_compress.c index bbe6421fb..f7ca2d3bb 100644 --- a/libfenrir/src/main/jni/compress/zstd/compress/huf_compress.c +++ b/libfenrir/src/main/jni/compress/zstd/compress/huf_compress.c @@ -386,7 +386,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 targetNbBits /* renorm totalCost from 2^largestBits to 2^targetNbBits * note : totalCost is necessarily a multiple of baseCost */ - assert((totalCost & (baseCost - 1)) == 0); + assert(((U32)totalCost & (baseCost - 1)) == 0); totalCost >>= (largestBits - targetNbBits); assert(totalCost > 0); @@ -1253,41 +1253,59 @@ unsigned HUF_minTableLog(unsigned symbolCardinality) return minBitsSymbols; } -unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, void* workSpace, size_t wkspSize, HUF_CElt* table, const unsigned* count, HUF_depth_mode depthMode) +unsigned HUF_optimalTableLog( + unsigned maxTableLog, + size_t srcSize, + unsigned maxSymbolValue, + void* workSpace, size_t wkspSize, + HUF_CElt* table, + const unsigned* count, + HUF_depth_mode depthMode) { - unsigned optLog = FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1); assert(srcSize > 1); /* Not supported, RLE should be used instead */ + assert(wkspSize >= sizeof(HUF_buildCTable_wksp_tables)); - if (depthMode == HUF_depth_optimal) { /** Test valid depths and return optimal **/ - BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp); + if (depthMode != HUF_depth_optimal) { + /* cheap evaluation, based on FSE */ + return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1); + } + + { BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp); size_t dstSize = wkspSize - sizeof(HUF_WriteCTableWksp); - size_t optSize = ((size_t) ~0); - unsigned huffLog; size_t maxBits, hSize, newSize; const unsigned symbolCardinality = HUF_cardinality(count, maxSymbolValue); + const unsigned minTableLog = HUF_minTableLog(symbolCardinality); + size_t optSize = ((size_t) ~0) - 1; + unsigned optLog = maxTableLog, optLogGuess; - if (wkspSize < sizeof(HUF_buildCTable_wksp_tables)) return optLog; + DEBUGLOG(6, "HUF_optimalTableLog: probing huf depth (srcSize=%zu)", srcSize); - for (huffLog = HUF_minTableLog(symbolCardinality); huffLog <= maxTableLog; huffLog++) { - maxBits = HUF_buildCTable_wksp(table, count, - maxSymbolValue, huffLog, - workSpace, wkspSize); + /* Search until size increases */ + for (optLogGuess = minTableLog; optLogGuess <= maxTableLog; optLogGuess++) { + DEBUGLOG(7, "checking for huffLog=%u", optLogGuess); + maxBits = HUF_buildCTable_wksp(table, count, maxSymbolValue, optLogGuess, workSpace, wkspSize); if (ERR_isError(maxBits)) continue; - hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, - workSpace, wkspSize); + if (maxBits < optLogGuess && optLogGuess > minTableLog) break; + + hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, workSpace, wkspSize); + if (ERR_isError(hSize)) continue; newSize = HUF_estimateCompressedSize(table, count, maxSymbolValue) + hSize; + if (newSize > optSize + 1) { + break; + } + if (newSize < optSize) { optSize = newSize; - optLog = huffLog; + optLog = optLogGuess; } } + assert(optLog <= HUF_TABLELOG_MAX); + return optLog; } - assert(optLog <= HUF_TABLELOG_MAX); - return optLog; } /* HUF_compress_internal() : diff --git a/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress.c b/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress.c index 759abe00a..b12cacc77 100644 --- a/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress.c +++ b/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress.c @@ -2727,15 +2727,14 @@ ZSTD_entropyCompressSeqStore_internal( unsigned const suspectUncompressible = (numSequences == 0) || (numLiterals / numSequences >= SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO); size_t const litSize = (size_t)(seqStorePtr->lit - literals); - HUF_depth_mode depthMode = cctxParams->cParams.strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD ? HUF_depth_optimal : HUF_depth_fast; size_t const cSize = ZSTD_compressLiterals( - &prevEntropy->huf, &nextEntropy->huf, - cctxParams->cParams.strategy, - ZSTD_literalsCompressionIsDisabled(cctxParams), op, dstCapacity, literals, litSize, entropyWorkspace, entropyWkspSize, - bmi2, suspectUncompressible, depthMode); + &prevEntropy->huf, &nextEntropy->huf, + cctxParams->cParams.strategy, + ZSTD_literalsCompressionIsDisabled(cctxParams), + suspectUncompressible, bmi2); FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed"); assert(cSize <= dstCapacity); op += cSize; @@ -3878,12 +3877,12 @@ ZSTD_deriveBlockSplitsHelper(seqStoreSplits* splits, size_t startIdx, size_t end size_t estimatedSecondHalfSize; size_t midIdx = (startIdx + endIdx)/2; + DEBUGLOG(5, "ZSTD_deriveBlockSplitsHelper: startIdx=%zu endIdx=%zu", startIdx, endIdx); assert(endIdx >= startIdx); if (endIdx - startIdx < MIN_SEQUENCES_BLOCK_SPLITTING || splits->idx >= ZSTD_MAX_NB_BLOCK_SPLITS) { DEBUGLOG(6, "ZSTD_deriveBlockSplitsHelper: Too few sequences (%zu)", endIdx - startIdx); return; } - DEBUGLOG(5, "ZSTD_deriveBlockSplitsHelper: startIdx=%zu endIdx=%zu", startIdx, endIdx); ZSTD_deriveSeqStoreChunk(fullSeqStoreChunk, origSeqStore, startIdx, endIdx); ZSTD_deriveSeqStoreChunk(firstHalfSeqStore, origSeqStore, startIdx, midIdx); ZSTD_deriveSeqStoreChunk(secondHalfSeqStore, origSeqStore, midIdx, endIdx); diff --git a/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_internal.h b/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_internal.h index f755a1f79..bb5e25083 100644 --- a/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_internal.h +++ b/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_internal.h @@ -582,7 +582,7 @@ MEM_STATIC size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat) { U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6; ZSTD_STATIC_ASSERT(ZSTD_btultra == 8); - assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); + assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, (int)strat)); return (srcSize >> minlog) + 2; } diff --git a/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_literals.c b/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_literals.c index 972d40e71..666e5315d 100644 --- a/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_literals.c +++ b/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_literals.c @@ -92,16 +92,37 @@ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* return flSize+1; } -size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, - ZSTD_hufCTables_t* nextHuf, - ZSTD_strategy strategy, int disableLiteralCompression, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize, - void* entropyWorkspace, size_t entropyWorkspaceSize, - const int bmi2, - unsigned suspectUncompressible, HUF_depth_mode depthMode) +/* ZSTD_minLiteralsToCompress() : + * returns minimal amount of literals + * for literal compression to even be attempted. + * Minimum is made tighter as compression strategy increases. + */ +static size_t +ZSTD_minLiteralsToCompress(ZSTD_strategy strategy, HUF_repeat huf_repeat) +{ + assert((int)strategy >= 0); + assert((int)strategy <= 9); + /* btultra2 : min 8 bytes; + * then 2x larger for each successive compression strategy + * max threshold 64 bytes */ + { int const shift = MIN(9-strategy, 3); + size_t const mintc = (huf_repeat == HUF_repeat_valid) ? 6 : 8 << shift; + DEBUGLOG(7, "minLiteralsToCompress = %zu", mintc); + return mintc; + } +} + +size_t ZSTD_compressLiterals ( + void* dst, size_t dstCapacity, + const void* src, size_t srcSize, + void* entropyWorkspace, size_t entropyWorkspaceSize, + const ZSTD_hufCTables_t* prevHuf, + ZSTD_hufCTables_t* nextHuf, + ZSTD_strategy strategy, + int disableLiteralCompression, + int suspectUncompressible, + int bmi2) { - size_t const minGain = ZSTD_minGain(srcSize, strategy); size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); BYTE* const ostart = (BYTE*)dst; U32 singleStream = srcSize < 256; @@ -119,15 +140,14 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, if (disableLiteralCompression) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - /* small ? don't even attempt compression (speed opt) */ -# define COMPRESS_LITERALS_SIZE_MIN 63 - { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; - if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - } + /* if too small, don't even attempt compression (speed opt) */ + if (srcSize < ZSTD_minLiteralsToCompress(strategy, prevHuf->repeatMode)) + return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression"); { HUF_repeat repeat = prevHuf->repeatMode; int const preferRepeat = (strategy < ZSTD_lazy) ? srcSize <= 1024 : 0; + HUF_depth_mode const depthMode = (strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD) ? HUF_depth_optimal : HUF_depth_fast; typedef size_t (*huf_compress_f)(void*, size_t, const void*, size_t, unsigned, unsigned, void*, size_t, HUF_CElt*, HUF_repeat*, int, int, unsigned, HUF_depth_mode); huf_compress_f huf_compress; if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; @@ -146,10 +166,11 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, } } - if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) { - ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); - return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - } + { size_t const minGain = ZSTD_minGain(srcSize, strategy); + if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) { + ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); + return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + } } if (cLitSize==1) { ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); diff --git a/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_literals.h b/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_literals.h index e5da204c8..9eb74729d 100644 --- a/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_literals.h +++ b/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress_literals.h @@ -18,14 +18,18 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize); -/* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */ -size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, - ZSTD_hufCTables_t* nextHuf, - ZSTD_strategy strategy, int disableLiteralCompression, - void* dst, size_t dstCapacity, +/* ZSTD_compressLiterals(): + * @entropyWorkspace: must be aligned on 4-bytes boundaries + * @entropyWorkspaceSize : must be >= HUF_WORKSPACE_SIZE + * @suspectUncompressible: sampling checks, to potentially skip huffman coding + */ +size_t ZSTD_compressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize, void* entropyWorkspace, size_t entropyWorkspaceSize, - const int bmi2, - unsigned suspectUncompressible, HUF_depth_mode depthMode); + const ZSTD_hufCTables_t* prevHuf, + ZSTD_hufCTables_t* nextHuf, + ZSTD_strategy strategy, int disableLiteralCompression, + int suspectUncompressible, + int bmi2); #endif /* ZSTD_COMPRESS_LITERALS_H */ diff --git a/libfenrir/src/main/jni/compress/zstd/compress/zstd_opt.c b/libfenrir/src/main/jni/compress/zstd/compress/zstd_opt.c index 9b14093cb..fdd7f9d8b 100644 --- a/libfenrir/src/main/jni/compress/zstd/compress/zstd_opt.c +++ b/libfenrir/src/main/jni/compress/zstd/compress/zstd_opt.c @@ -16,7 +16,7 @@ #define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */ #define ZSTD_MAX_PRICE (1<<30) -#define ZSTD_PREDEF_THRESHOLD 1024 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */ +#define ZSTD_PREDEF_THRESHOLD 8 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */ /*-************************************* @@ -65,7 +65,7 @@ MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat) /* debugging function, * @return price in bytes as fractional value * for debug messages only */ -MEM_STATIC double ZSTD_fCost(U32 price) +MEM_STATIC double ZSTD_fCost(int price) { return (double)price / (BITCOST_MULTIPLIER*8); } @@ -96,14 +96,18 @@ static U32 sum_u32(const unsigned table[], size_t nbElts) return total; } -static U32 ZSTD_downscaleStats(unsigned* table, U32 lastEltIndex, U32 shift) +typedef enum { base_0possible=0, base_1guaranteed=1 } base_directive_e; + +static U32 +ZSTD_downscaleStats(unsigned* table, U32 lastEltIndex, U32 shift, base_directive_e base1) { U32 s, sum=0; DEBUGLOG(5, "ZSTD_downscaleStats (nbElts=%u, shift=%u)", (unsigned)lastEltIndex+1, (unsigned)shift ); assert(shift < 30); for (s=0; s> shift); + unsigned const base = base1 ? 1 : (table[s]>0); + unsigned const newStat = base + (table[s] >> shift); sum += newStat; table[s] = newStat; } @@ -120,7 +124,7 @@ static U32 ZSTD_scaleStats(unsigned* table, U32 lastEltIndex, U32 logTarget) DEBUGLOG(5, "ZSTD_scaleStats (nbElts=%u, target=%u)", (unsigned)lastEltIndex+1, (unsigned)logTarget); assert(logTarget < 30); if (factor <= 1) return prevsum; - return ZSTD_downscaleStats(table, lastEltIndex, ZSTD_highbit32(factor)); + return ZSTD_downscaleStats(table, lastEltIndex, ZSTD_highbit32(factor), base_1guaranteed); } /* ZSTD_rescaleFreqs() : @@ -202,14 +206,14 @@ ZSTD_rescaleFreqs(optState_t* const optPtr, optPtr->offCodeSum += optPtr->offCodeFreq[of]; } } - } else { /* huf.repeatMode != HUF_repeat_valid => presumed not a dictionary */ + } else { /* first block, no dictionary */ assert(optPtr->litFreq != NULL); if (compressedLiterals) { /* base initial cost of literals on direct frequency within src */ unsigned lit = MaxLit; HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */ - optPtr->litSum = ZSTD_downscaleStats(optPtr->litFreq, MaxLit, 8); + optPtr->litSum = ZSTD_downscaleStats(optPtr->litFreq, MaxLit, 8, base_0possible); } { unsigned const baseLLfreqs[MaxLL+1] = { @@ -571,16 +575,17 @@ void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) { ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict); } -FORCE_INLINE_TEMPLATE -U32 ZSTD_insertBtAndGetAllMatches ( - ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */ - ZSTD_matchState_t* ms, - U32* nextToUpdate3, - const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode, - const U32 rep[ZSTD_REP_NUM], - U32 const ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */ - const U32 lengthToBeat, - U32 const mls /* template */) +FORCE_INLINE_TEMPLATE U32 +ZSTD_insertBtAndGetAllMatches ( + ZSTD_match_t* matches, /* store result (found matches) in this table (presumed large enough) */ + ZSTD_matchState_t* ms, + U32* nextToUpdate3, + const BYTE* const ip, const BYTE* const iLimit, + const ZSTD_dictMode_e dictMode, + const U32 rep[ZSTD_REP_NUM], + const U32 ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */ + const U32 lengthToBeat, + const U32 mls /* template */) { const ZSTD_compressionParameters* const cParams = &ms->cParams; U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); @@ -1147,7 +1152,7 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms, U32 const matchPrice = ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel); U32 const sequencePrice = literalsPrice + matchPrice; DEBUGLOG(7, "rPos:%u => set initial price : %.2f", - pos, ZSTD_fCost(sequencePrice)); + pos, ZSTD_fCost((int)sequencePrice)); opt[pos].mlen = pos; opt[pos].off = offBase; opt[pos].litlen = litlen; diff --git a/libfenrir/src/main/jni/rlottie/src/lottie/rapidjson/error/error.h b/libfenrir/src/main/jni/rlottie/src/lottie/rapidjson/error/error.h index 8bdc39541..cae345db3 100644 --- a/libfenrir/src/main/jni/rlottie/src/lottie/rapidjson/error/error.h +++ b/libfenrir/src/main/jni/rlottie/src/lottie/rapidjson/error/error.h @@ -42,7 +42,7 @@ RAPIDJSON_DIAG_OFF(padded) /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_STRING -//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. +//! Macro for converting string literal to \ref RAPIDJSON_ERROR_CHARTYPE[]. /*! \ingroup RAPIDJSON_ERRORS By default this conversion macro does nothing. On Windows, user can define this macro as \c _T(x) for supporting both