diff --git a/app_fenrir/build.gradle b/app_fenrir/build.gradle index a33948216..21884db4a 100644 --- a/app_fenrir/build.gradle +++ b/app_fenrir/build.gradle @@ -162,6 +162,7 @@ dependencies { implementation("androidx.collection:collection-ktx:$collectionVersion") implementation("androidx.savedstate:savedstate-ktx:$savedStateVersion") implementation("androidx.cardview:cardview:$cardviewVersion") + implementation("androidx.concurrent:concurrent-futures:$concurentVersion") //implementation("androidx.camera:camera-core:$cameraVersion") //implementation("androidx.camera:camera-lifecycle:$cameraVersion") //implementation("androidx.camera:camera-view:$cameraVersion") diff --git a/app_fenrir/src/main/res/drawable/client.xml b/app_fenrir/src/fenrir/res/drawable/client.xml similarity index 98% rename from app_fenrir/src/main/res/drawable/client.xml rename to app_fenrir/src/fenrir/res/drawable/client.xml index 981c2e8a7..a9db81de7 100644 --- a/app_fenrir/src/main/res/drawable/client.xml +++ b/app_fenrir/src/fenrir/res/drawable/client.xml @@ -1,10 +1,12 @@ + android:pathData="M14.2578,20.1523L15.1797,18.7031C15.6055,18.0352 16.0313,17.3672 16.4531,16.6992C16.6406,16.4102 16.9844,16.3516 17.2305,16.5625C17.2734,16.6016 17.3125,16.6484 17.3438,16.6992C18.082,17.8281 18.8203,18.957 19.5586,20.0898C19.5664,20.1055 19.5781,20.1211 19.5938,20.1523L19.4961,20.1523C19.168,20.1523 18.8398,20.1523 18.5117,20.1563C18.4453,20.1563 18.4102,20.1367 18.375,20.082C17.9063,19.3594 17.4375,18.6367 16.9648,17.9141C16.9453,17.8867 16.9258,17.8633 16.9023,17.8281L16.5313,18.4102C16.1797,18.9648 15.8281,19.5234 15.4727,20.0781C15.4375,20.1367 15.3984,20.1563 15.332,20.1563C14.9805,20.1523 14.6289,20.1523 14.2578,20.1523ZM16.9531,21.2852C17.168,20.9531 17.3711,20.6406 17.5781,20.332C17.5938,20.3047 17.6484,20.293 17.6836,20.2891C18.6055,20.2813 19.5234,20.2734 20.4414,20.2695L20.5625,20.2695C20.5352,20.2227 20.5156,20.1875 20.4922,20.1523C20.043,19.4648 19.5938,18.7734 19.1406,18.0859C19.1016,18.0234 19.0938,17.9805 19.1406,17.9141C19.3164,17.6484 19.4883,17.3789 19.668,17.1016C19.6875,17.1289 19.7031,17.1445 19.7148,17.1602C20.4258,18.25 21.1367,19.3438 21.8516,20.4375C22.0625,20.7617 21.9297,21.1484 21.5703,21.2344C21.4492,21.2617 21.3242,21.2578 21.1992,21.2578C20.2852,21.2656 19.3711,21.2695 18.4609,21.2734C18,21.2773 17.5391,21.2813 17.082,21.2852ZM20.0117,22.8633C19.5859,22.8633 19.1797,22.8633 18.7773,22.8633C17.7148,22.8711 16.6563,22.8789 15.5977,22.8867C15.375,22.8867 15.1992,22.8125 15.0938,22.6094C14.9961,22.4258 15.0234,22.2461 15.1328,22.0742C15.3359,21.7539 15.543,21.4297 15.75,21.1094C16.2461,20.3281 16.7422,19.5469 17.2383,18.7656C17.2539,18.7383 17.2734,18.7109 17.2969,18.6758C17.4219,18.8672 17.543,19.0508 17.6602,19.2344C17.7188,19.3242 17.7773,19.4219 17.8398,19.5078C17.8828,19.5625 17.8711,19.6016 17.8359,19.6563C17.3867,20.3594 16.9375,21.0664 16.4922,21.7734C16.4688,21.8047 16.4492,21.8359 16.4219,21.8828C16.6133,21.8828 16.7852,21.8828 16.957,21.8828C17.7227,21.875 18.4883,21.8711 19.2539,21.8633C19.3242,21.8633 19.3789,21.8711 19.418,21.9375C19.6055,22.2305 19.7969,22.5156 19.9844,22.8086C19.9922,22.8164 19.9961,22.8281 20.0117,22.8633ZM16.9258,14.6875L13.3516,20.3086L16.082,20.3086C16.0625,20.3359 16.0508,20.3672 16.0352,20.3906C15.8594,20.6641 15.6797,20.9336 15.5078,21.2031C15.4648,21.2734 15.4141,21.3008 15.3359,21.3008C14.5508,21.3008 13.7695,21.3086 12.9844,21.3125C12.8242,21.3125 12.6641,21.3125 12.5078,21.3164C12.293,21.3203 12.125,21.2383 12.0195,21.043C11.918,20.8477 11.9531,20.668 12.0664,20.4922C13.5352,18.1875 15,15.8828 16.4648,13.5781C16.6992,13.207 17.1328,13.2031 17.3711,13.5664C17.8711,14.3359 18.3711,15.1016 18.8711,15.8672C18.9102,15.9219 18.9102,15.9609 18.875,16.0156C18.7109,16.2617 18.5547,16.5078 18.3945,16.7539C18.375,16.7813 18.3594,16.8047 18.332,16.8438ZM20.8516,21.8516L23.6484,21.8516L20,16.2539C19.5391,16.9805 19.0859,17.6875 18.6289,18.4102C18.5664,18.3242 18.5117,18.2461 18.457,18.1641C18.332,17.9727 18.207,17.7773 18.0781,17.5859C18.0469,17.5352 18.0391,17.5 18.0742,17.4453C18.5664,16.6758 19.0547,15.9063 19.5469,15.1367C19.7734,14.7773 20.207,14.7734 20.4414,15.1328C21.9336,17.4219 23.4297,19.7148 24.9258,22.0078C25.1641,22.375 24.9688,22.7969 24.5352,22.8164C24.1055,22.8398 23.6758,22.8281 23.2422,22.832C22.6953,22.8359 22.1484,22.8398 21.5977,22.8438C21.5352,22.8438 21.4922,22.8281 21.457,22.7695C21.2656,22.4727 21.0664,22.1758 20.8516,21.8516ZM14.6133,21.4258L13.3242,23.457L20.5469,23.4063L19.2539,21.4258L19.6406,21.4258C19.875,21.4258 20.1133,21.4258 20.3477,21.4219C20.4063,21.4219 20.4414,21.4375 20.4727,21.4883C20.9258,22.1875 21.3789,22.8789 21.832,23.5781C22.043,23.9023 21.9063,24.2891 21.5469,24.375C21.4297,24.4023 21.3008,24.3945 21.1758,24.3984C20.3906,24.4023 19.6055,24.4063 18.8164,24.4102C16.8359,24.4219 14.8516,24.4375 12.8672,24.4492C12.7344,24.4492 12.5977,24.4531 12.4648,24.4531C12.2578,24.4531 12.0977,24.3672 12,24.1797C11.9023,23.9922 11.9297,23.8164 12.0391,23.6445C12.2656,23.293 12.4883,22.9375 12.7148,22.5859C12.9453,22.2227 13.1758,21.8594 13.4063,21.4922C13.4297,21.4453 13.4805,21.418 13.5313,21.4219C13.8867,21.4258 14.2422,21.4258 14.6133,21.4258ZM21.2578,29.6953C21.6758,29.1094 21.9102,28.457 22.0234,27.7383C21.8438,27.8867 21.6992,28.0781 21.6133,28.2969C21.5195,28.5195 21.4375,28.75 21.3555,28.9805C21.2188,29.3516 20.9805,29.6172 20.5859,29.7773C20.8828,29.207 21.0352,28.6289 21.043,28.0313C20.5859,28.1328 20.1328,28.2461 19.6719,28.332C19.2148,28.4141 18.7461,28.4609 18.2539,28.5273C18.4453,28.6953 18.6094,28.8711 18.8086,29.0039C19.25,29.3008 19.707,29.5781 20.1602,29.8555C20.5586,30.1016 20.9727,30.3281 21.2773,30.6992C21.4805,30.9453 21.6563,31.2188 21.8438,31.4805C21.9219,31.5938 21.9922,31.707 22.0703,31.832L22.3047,31.5352C22.3164,31.5586 22.3242,31.582 22.3359,31.6094C22.4609,32.0781 22.6016,32.543 22.8633,32.957C23.1211,33.3594 23.4102,33.7344 23.8438,33.957C24.0156,34.0469 24.1992,34.1055 24.3789,34.1797C24.4102,34.1914 24.4414,34.2031 24.4727,34.2148C24.4727,34.2227 24.4688,34.2344 24.4688,34.2422C24.3984,34.2578 24.3281,34.2734 24.2578,34.2852C23.7695,34.3828 23.2813,34.4609 22.7852,34.4688C21.9453,34.4805 21.1406,34.2969 20.3633,33.9883C20.0352,33.8594 19.7109,33.7148 19.3906,33.5742C19.3555,33.5625 19.3242,33.5469 19.2852,33.5313C19.293,33.9609 19.4922,34.3008 19.6953,34.6406C19.6914,34.6484 19.6875,34.6563 19.6875,34.668C19.5742,34.6445 19.4609,34.625 19.3516,34.6055C18.8125,34.5 18.4023,34.1875 18.0742,33.7656C17.7617,33.3672 17.4688,32.9531 17.1602,32.5508C17.082,32.4453 16.9844,32.3555 16.8906,32.2656C16.8281,32.2109 16.75,32.2109 16.7031,32.2891C16.6523,32.3711 16.6094,32.4648 16.5781,32.5625C16.5352,32.7148 16.5156,32.8711 16.4727,33.0273C16.4414,33.1523 16.375,33.2656 16.25,33.3477C16.207,33.1992 16.168,33.0625 16.125,32.9297C15.9844,32.4961 15.8477,32.0547 15.6875,31.6289C15.5703,31.3125 15.3281,31.082 15.0586,30.8867C14.9258,30.9961 14.8945,31.1484 14.8945,31.3086C14.8906,31.5 14.9023,31.6914 14.8906,31.8828C14.8789,32.0117 14.8359,32.1328 14.8086,32.2578L14.7695,32.2578C14.7227,32.1328 14.6758,32.0078 14.6289,31.8828C14.3086,30.9688 13.7969,30.168 13.2344,29.3906C13.1875,29.3281 13.1406,29.2656 13.0977,29.1992C12.8867,28.8516 12.6094,28.5781 12.2773,28.3516C11.8672,28.0703 11.4648,27.7852 11.0156,27.5742C10.5352,27.3477 10.0508,27.3203 9.5547,27.5117C9.4688,27.5469 9.3867,27.582 9.2969,27.6055C9.2461,27.6172 9.1719,27.625 9.1367,27.5977C9.1094,27.5781 9.1133,27.4922 9.1289,27.4453C9.1758,27.3164 9.2344,27.1953 9.2891,27.0742C9.4063,26.8125 9.3828,26.7734 9.1016,26.7734L8.9453,26.7734C8.9727,26.7344 8.9883,26.707 9.0078,26.6836C9.4453,26.1875 9.8242,25.6406 10.1406,25.0586C10.2695,24.8164 10.3711,24.5703 10.418,24.2969C10.4258,24.2344 10.4258,24.168 10.418,24.1016C10.3516,23.4531 10.2773,22.8086 10.2148,22.1602C10.1875,21.8594 10.1836,21.5586 10.168,21.2578C10.1602,21.1992 10.1445,21.1484 10.1211,21.0977C9.8711,20.5742 9.6289,20.0469 9.4844,19.4805C9.3945,19.1211 9.3281,18.7578 9.2539,18.3945C9.25,18.3789 9.2461,18.3672 9.2383,18.332C9.1094,18.543 9.0078,18.7461 8.9609,18.9648C8.8438,19.5039 8.7422,20.0391 8.6289,20.5781C8.625,20.6094 8.6133,20.6406 8.5977,20.6719C8.5586,20.4063 8.3984,20.207 8.2539,19.9961C7.8398,19.4023 7.6523,18.7422 7.668,18.0195C7.6797,17.3711 7.7891,16.7422 8.0547,16.1484C8.2695,15.668 8.5898,15.2695 8.9766,14.9297C9.2344,14.7031 9.5078,14.5 9.7695,14.2852C9.8398,14.2305 9.8984,14.168 9.9531,14.0977C10.2578,13.6797 10.5781,13.2813 10.9648,12.9414C11.3164,12.625 11.7227,12.4219 12.1602,12.2695C12.3477,12.2031 12.5391,12.1445 12.7344,12.0781C12.2422,11.8984 11.7813,12.1055 11.3086,12.1641C11.7852,11.6055 12.4219,11.2383 12.9609,10.7148C12.7539,10.6719 12.5625,10.6289 12.3711,10.6016C12.0234,10.5547 11.6719,10.5234 11.3242,10.4766C11.1914,10.4648 11.0664,10.4063 10.9648,10.3203C11.1328,10.2422 11.2813,10.1641 11.4336,10.1055C11.6406,10.0313 11.8516,9.9766 12.0586,9.9063C12.1758,9.8633 12.293,9.8047 12.4219,9.7461C12.2891,9.6406 12.1484,9.6016 12.0078,9.5664C11.8945,9.543 11.7852,9.5195 11.6719,9.4883C11.5664,9.4531 11.4922,9.3789 11.457,9.2461C11.5547,9.2266 11.6445,9.207 11.7344,9.1953C12.3359,9.1211 12.8789,8.9063 13.3906,8.5781C13.7344,8.3555 14.0977,8.1563 14.457,7.9531C14.5547,7.8984 14.6172,7.8438 14.6211,7.7266C14.6211,7.6836 14.6367,7.6484 14.6445,7.5938C14.5898,7.6016 14.5469,7.6133 14.5,7.6172C13.9453,7.6641 13.3984,7.6602 12.8516,7.5625C12.7969,7.5508 12.7422,7.5352 12.6875,7.5195C12.3086,7.4023 12.2617,7.0234 12.4492,6.75C12.5547,6.5977 12.7148,6.5117 12.8789,6.4492C13.2734,6.3008 13.6719,6.1719 14.0625,6.0078C14.3281,5.8945 14.5781,5.7422 14.8242,5.5938C14.9141,5.5391 14.9922,5.4492 15.0547,5.3672C15.6992,4.5039 16.5469,3.9375 17.543,3.5859C17.8984,3.4609 18.25,3.3242 18.6016,3.2031C18.8672,3.1172 19.1055,2.9531 19.2813,2.7344C19.4844,2.4844 19.6836,2.2266 19.8984,1.9766C20.0234,1.832 20.1563,1.6875 20.3086,1.5703C20.5234,1.4023 20.7695,1.3086 21.0469,1.3398C21.2031,1.3555 21.332,1.4375 21.4414,1.5391C21.918,1.9922 22.1523,2.543 22.1055,3.207C22.0859,3.4883 22.0469,3.7656 22.0156,4.0547C22.0898,3.9805 22.1523,3.9023 22.2305,3.8438C22.3438,3.7617 22.457,3.668 22.5859,3.6289C22.8867,3.5391 23.1563,3.7578 23.1563,4.0742C23.1563,4.3516 23.1016,4.625 22.9531,4.8594C22.6914,5.2813 22.418,5.6992 22.1445,6.1133C21.9141,6.457 21.6797,6.793 21.5586,7.1953C21.4375,7.5898 21.543,7.9492 21.7461,8.2734C21.8516,8.4414 22.043,8.5391 22.2383,8.5938C22.2773,8.6016 22.3164,8.6133 22.3555,8.625C22.3555,8.6367 22.3555,8.6445 22.3555,8.6563L22.1211,8.6992C22.2305,8.9688 22.457,9.0664 22.7109,9.1797L22.4922,9.3633C22.6211,9.5391 22.8125,9.6484 23,9.7617C23.0703,9.8008 23.1406,9.8398 23.2148,9.8711C23.293,9.9063 23.293,9.9453 23.2344,9.9922C23.1719,10.0508 23.1094,10.1055 23.0391,10.168C23.1523,10.3281 23.293,10.4648 23.4531,10.5781C23.5156,10.625 23.582,10.668 23.6484,10.7109C23.7031,10.7461 23.7031,10.7813 23.6484,10.8125C23.5625,10.8633 23.4727,10.9141 23.3789,10.9648C23.3984,11.0039 23.4258,11.0508 23.4492,11.0938C23.7578,11.5977 24.0586,12.1094 24.2344,12.6758C24.375,13.1172 24.4727,13.5703 24.5625,14.0234C24.7188,14.8242 24.9844,15.6016 25.3555,16.3281C25.3711,16.3594 25.3906,16.3945 25.4102,16.4258L25.4375,16.4219C25.4531,16.0586 25.4727,15.6914 25.4844,15.3281C25.5039,14.6367 25.3359,13.9844 25.1055,13.3438C24.9531,12.9141 24.7852,12.4883 24.6289,12.0625C24.6133,12.0313 24.6094,11.9922 24.5938,11.9297C24.6172,11.9453 24.6367,11.9609 24.6563,11.9766C25.043,12.4063 25.4336,12.832 25.75,13.3203C26.1094,13.875 26.332,14.4883 26.4609,15.1328C26.5547,15.5781 26.6172,16.0234 26.6992,16.4727C26.707,16.5156 26.7344,16.5547 26.7734,16.582C27.0977,16.7852 27.418,16.9961 27.6719,17.2891C27.9844,17.6523 28.1523,18.0859 28.2344,18.5508C28.4141,19.5703 28.3672,20.5742 27.9297,21.5313C27.7656,21.8945 27.5547,22.2383 27.375,22.6016C27.0898,23.1758 26.8672,23.7813 26.7344,24.4141C26.6914,24.6289 26.6953,24.8555 26.6992,25.0742C26.707,25.4141 26.668,25.7578 26.5859,26.0859C26.5664,26.1758 26.5391,26.1641 26.4766,26.125C26.3945,26.0703 26.3047,26.0313 26.2148,25.9844L26.1797,26.0039C26.2148,26.2344 26.2539,26.4648 26.2891,26.6953L26.2617,26.707C26.2344,26.6914 26.2109,26.6758 26.1875,26.6563C25.8164,26.3398 25.4063,26.0898 24.9453,25.9219C24.7266,25.8438 24.5273,25.7109 24.3086,25.5938C24.2031,25.7148 24.0703,25.8398 23.9648,25.9883C23.6641,26.418 23.3516,26.8398 23.0859,27.2891C22.8672,27.6523 22.6953,28.0508 22.5156,28.4414C22.3594,28.7773 22.1289,29.0508 21.8516,29.2852C21.668,29.4336 21.4805,29.5742 21.2969,29.7188ZM25.625,20.4375C25.6289,16.2656 22.3086,12.8516 18.1641,12.8242C13.9961,12.7969 10.6289,16.1953 10.6055,20.3867C10.582,24.6172 13.9492,28.0156 18.0625,28.0391C22.2422,28.0664 25.625,24.6406 25.625,20.4375ZM25.625,20.4375" + tools:ignore="VectorPath" /> diff --git a/app_fenrir/src/fenrir/res/drawable/client_round.xml b/app_fenrir/src/fenrir/res/drawable/client_round.xml new file mode 100644 index 000000000..437c88d76 --- /dev/null +++ b/app_fenrir/src/fenrir/res/drawable/client_round.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app_fenrir/src/kate/res/drawable/client.xml b/app_fenrir/src/kate/res/drawable/client.xml new file mode 100644 index 000000000..fdfaaf67d --- /dev/null +++ b/app_fenrir/src/kate/res/drawable/client.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app_fenrir/src/kate/res/drawable/client_round.xml b/app_fenrir/src/kate/res/drawable/client_round.xml new file mode 100644 index 000000000..9d04c3c2e --- /dev/null +++ b/app_fenrir/src/kate/res/drawable/client_round.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app_fenrir/src/main/AndroidManifest.xml b/app_fenrir/src/main/AndroidManifest.xml index cb143b4d2..e36b34188 100644 --- a/app_fenrir/src/main/AndroidManifest.xml +++ b/app_fenrir/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ + ("LikesListResponse") { val itemRoot = itemsArray?.get(i)?.asJsonObject val type = optString(itemRoot, "type") var owner: VKApiOwner? = null - if ("profile" == type) { + if ("profile" == type || "user" == type) { owner = itemRoot?.let { kJson.decodeFromJsonElement(VKApiUser.serializer(), it) } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/ViewersListAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/ViewersListAdapter.kt new file mode 100644 index 000000000..cde429619 --- /dev/null +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/adapters/ViewersListAdapter.kt @@ -0,0 +1,47 @@ +package dev.ragnarok.fenrir.api.adapters + +import dev.ragnarok.fenrir.api.model.VKApiUser +import dev.ragnarok.fenrir.api.model.response.ViewersListResponse +import dev.ragnarok.fenrir.kJson +import dev.ragnarok.fenrir.orZero +import dev.ragnarok.fenrir.requireNonNull +import dev.ragnarok.fenrir.util.serializeble.json.JsonElement + +class ViewersListAdapter : AbsAdapter("ViewersListAdapter") { + @Throws(Exception::class) + override fun deserialize( + json: JsonElement + ): ViewersListResponse { + if (!checkObject(json)) { + throw Exception("$TAG error parse object") + } + val response = ViewersListResponse() + val root = json.asJsonObject + response.count = optInt(root, "count") + if (hasArray(root, "items")) { + val itemsArray = root.getAsJsonArray("items") + response.owners = ArrayList(itemsArray?.size.orZero()) + for (i in 0 until itemsArray?.size.orZero()) { + if (!checkObject(itemsArray?.get(i))) { + continue + } + val itemRoot = itemsArray?.get(i)?.asJsonObject + if (!hasObject(itemRoot, "user")) { + continue + } + val userRoot = itemRoot["user"] + val owner = userRoot?.let { + kJson.decodeFromJsonElement(VKApiUser.serializer(), it) + } + owner.requireNonNull { + response.owners?.add(it) + } + } + } + return response + } + + companion object { + private val TAG = ViewersListAdapter::class.java.simpleName + } +} \ No newline at end of file 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 6167b18a8..50ab00352 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 @@ -1,5 +1,6 @@ package dev.ragnarok.fenrir.api.impl +import dev.ragnarok.fenrir.Constants.DEVICE_COUNTRY_CODE import dev.ragnarok.fenrir.Includes.provideApplicationContext import dev.ragnarok.fenrir.api.ApiException import dev.ragnarok.fenrir.api.AuthException @@ -19,9 +20,19 @@ import io.reactivex.rxjava3.functions.Function class AuthApi(private val service: IDirectLoginSeviceProvider) : IAuthApi { override fun directLogin( - grantType: String?, clientId: Int, clientSecret: String?, - username: String?, pass: String?, v: String?, twoFaSupported: Boolean, - scope: String?, code: String?, captchaSid: String?, captchaKey: String?, forceSms: Boolean + grantType: String?, + clientId: Int, + clientSecret: String?, + username: String?, + pass: String?, + v: String?, + twoFaSupported: Boolean, + scope: String?, + code: String?, + captchaSid: String?, + captchaKey: String?, + forceSms: Boolean, + libverify_support: Boolean ): Single { return service.provideAuthService() .flatMap { service -> @@ -38,11 +49,12 @@ class AuthApi(private val service: IDirectLoginSeviceProvider) : IAuthApi { code, captchaSid, captchaKey, - if (forceSms) 1 else 0, + if (forceSms) 1 else null, getDeviceId( provideApplicationContext() ), - 1 + if (libverify_support) 1 else null, + DEVICE_COUNTRY_CODE ) .flatMap { response -> when { @@ -86,12 +98,17 @@ class AuthApi(private val service: IDirectLoginSeviceProvider) : IAuthApi { clientId: Int, clientSecret: String?, sid: String?, - v: String? + v: String?, + libverify_support: Boolean ): Single { return service.provideAuthService() .flatMap { service -> service - .validatePhone(apiId, clientId, clientSecret, sid, v) + .validatePhone( + apiId, clientId, clientSecret, sid, v, getDeviceId( + provideApplicationContext() + ), if (libverify_support) 1 else null, DEVICE_COUNTRY_CODE + ) .map(extractResponseWithErrorHandling()) } } @@ -119,7 +136,8 @@ class AuthApi(private val service: IDirectLoginSeviceProvider) : IAuthApi { deviceId, sakVersion, gaid, - v + v, + DEVICE_COUNTRY_CODE ) .flatMap { if (it.error != null) { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/LikesApi.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/LikesApi.kt index cc14977b6..659703c1a 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/LikesApi.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/impl/LikesApi.kt @@ -1,10 +1,12 @@ 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.ILikesApi import dev.ragnarok.fenrir.api.model.response.LikesListResponse +import dev.ragnarok.fenrir.api.model.response.ViewersListResponse import dev.ragnarok.fenrir.api.services.ILikesService import io.reactivex.rxjava3.core.Single @@ -26,6 +28,21 @@ internal class LikesApi(accountId: Long, provider: IServiceProvider) : } } + override fun getStoriesViewers( + ownerId: Long?, + storyId: Int?, + offset: Int?, count: Int? + ): Single { + return provideService(ILikesService(), TokenType.USER, TokenType.SERVICE) + .flatMap { service -> + service + .getStoriesViewers( + ownerId, storyId, offset, count, 1, Fields.FIELDS_BASE_USER + ) + .map(extractResponseWithErrorHandling()) + } + } + override fun delete( type: String?, ownerId: Long?, diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/interfaces/IAuthApi.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/interfaces/IAuthApi.kt index 9d42042b3..e47e25a81 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/interfaces/IAuthApi.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/interfaces/IAuthApi.kt @@ -7,9 +7,19 @@ import io.reactivex.rxjava3.core.Single interface IAuthApi { fun directLogin( - grantType: String?, clientId: Int, clientSecret: String?, - username: String?, pass: String?, v: String?, twoFaSupported: Boolean, - scope: String?, code: String?, captchaSid: String?, captchaKey: String?, forceSms: Boolean + grantType: String?, + clientId: Int, + clientSecret: String?, + username: String?, + pass: String?, + v: String?, + twoFaSupported: Boolean, + scope: String?, + code: String?, + captchaSid: String?, + captchaKey: String?, + forceSms: Boolean, + libverify_support: Boolean ): Single fun validatePhone( @@ -17,7 +27,8 @@ interface IAuthApi { clientId: Int, clientSecret: String?, sid: String?, - v: String? + v: String?, + libverify_support: Boolean ): Single fun authByExchangeToken( diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/interfaces/ILikesApi.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/interfaces/ILikesApi.kt index 41282396c..7992982bc 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/interfaces/ILikesApi.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/interfaces/ILikesApi.kt @@ -2,6 +2,7 @@ package dev.ragnarok.fenrir.api.interfaces import androidx.annotation.CheckResult import dev.ragnarok.fenrir.api.model.response.LikesListResponse +import dev.ragnarok.fenrir.api.model.response.ViewersListResponse import io.reactivex.rxjava3.core.Single interface ILikesApi { @@ -11,6 +12,14 @@ interface ILikesApi { friendsOnly: Boolean?, offset: Int?, count: Int?, skipOwn: Boolean?, fields: String? ): Single + @CheckResult + fun getStoriesViewers( + ownerId: Long?, + storyId: Int?, + offset: Int?, + count: Int? + ): Single + @CheckResult fun delete(type: String?, ownerId: Long?, itemId: Int, accessKey: String?): Single diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/response/ViewersListResponse.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/response/ViewersListResponse.kt new file mode 100644 index 000000000..0d0f6f9c9 --- /dev/null +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/model/response/ViewersListResponse.kt @@ -0,0 +1,11 @@ +package dev.ragnarok.fenrir.api.model.response + +import dev.ragnarok.fenrir.api.adapters.ViewersListAdapter +import dev.ragnarok.fenrir.api.model.VKApiOwner +import kotlinx.serialization.Serializable + +@Serializable(with = ViewersListAdapter::class) +class ViewersListResponse { + var count = 0 + var owners: ArrayList? = null +} \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/services/IAuthService.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/services/IAuthService.kt index 7ebbe90ed..06f258ea3 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/services/IAuthService.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/services/IAuthService.kt @@ -22,25 +22,28 @@ class IAuthService : IServiceRest() { captchaKey: String?, forceSms: Int?, device_id: String?, - libverify_support: Int? + libverify_support: Int?, + lang: String? ): Single { return rest.request( "token", form( - "grant_type" to grantType, - "client_id" to clientId, - "client_secret" to clientSecret, - "username" to username, + "libverify_support" to libverify_support, "password" to password, - "v" to v, + "code" to smscode, + "grant_type" to grantType, "2fa_supported" to twoFaSupported, + "v" to v, "scope" to scope, - "code" to smscode, + "client_secret" to clientSecret, + "client_id" to clientId, + "username" to username, "captcha_sid" to captchaSid, "captcha_key" to captchaKey, "force_sms" to forceSms, "device_id" to device_id, - "libverify_support" to libverify_support + "lang" to lang, + "https" to 1 ), LoginResponse.serializer(), false ) } @@ -57,7 +60,8 @@ class IAuthService : IServiceRest() { deviceId: String?, sakVersion: String?, gaid: String?, - v: String? + v: String?, + lang: String? ): Single { return rest.requestAndGetURLFromRedirects( "auth_by_exchange_token", @@ -70,7 +74,9 @@ class IAuthService : IServiceRest() { "device_id" to deviceId, "sak_version" to sakVersion, "gaid" to gaid, - "v" to v + "v" to v, + "lang" to lang, + "https" to 1 ) ) } @@ -80,16 +86,23 @@ class IAuthService : IServiceRest() { clientId: Int, clientSecret: String?, sid: String?, - v: String? + v: String?, + device_id: String?, + libverify_support: Int?, + lang: String? ): Single> { return rest.request( "auth.validatePhone", form( + "libverify_support" to libverify_support, "api_id" to apiId, "client_id" to clientId, "client_secret" to clientSecret, "sid" to sid, - "v" to v + "v" to v, + "device_id" to device_id, + "lang" to lang, + "https" to 1 ), base(VKApiValidationResponse.serializer()) ) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/services/ILikesService.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/services/ILikesService.kt index 42ffad462..9aa7b9f25 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/services/ILikesService.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/api/services/ILikesService.kt @@ -3,6 +3,7 @@ package dev.ragnarok.fenrir.api.services import dev.ragnarok.fenrir.api.model.response.BaseResponse import dev.ragnarok.fenrir.api.model.response.LikeResponse import dev.ragnarok.fenrir.api.model.response.LikesListResponse +import dev.ragnarok.fenrir.api.model.response.ViewersListResponse import dev.ragnarok.fenrir.api.model.response.isLikeResponse import dev.ragnarok.fenrir.api.rest.IServiceRest import io.reactivex.rxjava3.core.Single @@ -39,6 +40,26 @@ class ILikesService : IServiceRest() { ) } + fun getStoriesViewers( + ownerId: Long?, + storyId: Int?, + offset: Int?, + count: Int?, + extended: Int?, + fields: String? + ): Single> { + return rest.request( + "stories.getViewers", form( + "owner_id" to ownerId, + "story_id" to storyId, + "offset" to offset, + "count" to count, + "extended" to extended, + "fields" to fields + ), base(ViewersListResponse.serializer()) + ) + } + //https://vk.com/dev/likes.delete fun delete( type: String?, 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 331df4f95..88c7df829 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 @@ -15,6 +15,7 @@ import dev.ragnarok.fenrir.model.Captcha import dev.ragnarok.fenrir.nonNullNoEmpty import dev.ragnarok.fenrir.trimmedNonNullNoEmpty import dev.ragnarok.fenrir.util.Utils.getCauseIfRuntime +import java.util.concurrent.TimeUnit class DirectAuthPresenter(savedInstanceState: Bundle?) : RxSupportPresenter(savedInstanceState) { @@ -61,7 +62,8 @@ class DirectAuthPresenter(savedInstanceState: Bundle?) : code, captchaSid, captchaCode, - forceSms + forceSms, + Constants.DEFAULT_ACCOUNT_TYPE == AccountType.VK_ANDROID ) .fromIOToMain() .subscribe({ response -> onLoginResponse(response) }) { t -> @@ -110,15 +112,17 @@ class DirectAuthPresenter(savedInstanceState: Bundle?) : } } } - if (!sid.isNullOrEmpty()) { + if (!sid.isNullOrEmpty() && requireSmsCode) { appendDisposable(networker.vkAuth() .validatePhone( Constants.API_ID, Constants.API_ID, Constants.SECRET, sid, - Constants.AUTH_VERSION + Constants.AUTH_VERSION, + true ) + .delay(1, TimeUnit.SECONDS) .fromIOToMain() .subscribe({ }) { showError(getCauseIfRuntime(t)) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/ILikesInteractor.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/ILikesInteractor.kt index 057be5fcc..95908af37 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/ILikesInteractor.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/domain/ILikesInteractor.kt @@ -14,6 +14,14 @@ interface ILikesInteractor { offset: Int ): Single> + fun getStoriesViewers( + accountId: Long, + ownerId: Long, + storyId: Int, + count: Int, + offset: Int + ): Single> + companion object { const val FILTER_LIKES = "likes" const val FILTER_COPIES = "copies" 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 359864be5..e17399152 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 @@ -41,4 +41,29 @@ class LikesInteractor(private val networker: INetworker) : ILikesInteractor { owners } } + + override fun getStoriesViewers( + accountId: Long, + ownerId: Long, + storyId: Int, + count: Int, + offset: Int + ): Single> { + return networker.vkDefault(accountId) + .likes() + .getStoriesViewers( + ownerId, + storyId, + offset, + count + ) + .map { response -> + val dtos = listEmptyIfNull(response.owners) + val owners: MutableList = ArrayList(dtos.size) + for (dto in dtos) { + transformOwner(dto)?.let { owners.add(it) } + } + owners + } + } } \ No newline at end of file diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/PreferencesFragment.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/PreferencesFragment.kt index 8a8e87f8a..8f25b1827 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/PreferencesFragment.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/PreferencesFragment.kt @@ -643,14 +643,28 @@ class PreferencesFragment : AbsPreferencesFragment(), PreferencesAdapter.OnScree titleRes = R.string.webview_night_mode } - singleChoice( - "font_size", - selItems(R.array.array_font_size_names, R.array.array_font_size_items), - parentFragmentManager - ) { - initialSelection = "0" + seekBar("font_size_int") { + min = -3 + max = 9 + default = 0 + step = 1 + showTickMarks = true titleRes = R.string.font_size - onSelectionChange { + onSeek { + sleepDataDisposable.dispose() + sleepDataDisposable = Single.just(Any()) + .delay(1, TimeUnit.SECONDS) + .fromIOToMain() + .subscribe({ + requireActivity().recreate() + }, { RxUtils.dummy() }) + } + } + + switch("font_only_for_chats") { + defaultValue = false + titleRes = R.string.font_only_for_chats + onCheckedChange { requireActivity().recreate() } } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/abswall/AbsWallFragment.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/abswall/AbsWallFragment.kt index fb7350631..fdfbb7f7e 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/abswall/AbsWallFragment.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/abswall/AbsWallFragment.kt @@ -39,6 +39,7 @@ import dev.ragnarok.fenrir.modalbottomsheetdialogfragment.OptionRequest import dev.ragnarok.fenrir.model.* import dev.ragnarok.fenrir.module.FenrirNative import dev.ragnarok.fenrir.module.thorvg.ThorVGRender +import dev.ragnarok.fenrir.place.PlaceFactory import dev.ragnarok.fenrir.place.PlaceFactory.getAudiosPlace import dev.ragnarok.fenrir.place.PlaceFactory.getNarrativesPlace import dev.ragnarok.fenrir.place.PlaceFactory.getOwnerArticles @@ -190,13 +191,24 @@ abstract class AbsWallFragment> : LinearLayoutManager(requireActivity(), LinearLayoutManager.HORIZONTAL, false) mStoryAdapter = HorizontalStoryAdapter(mutableListOf()) mStoryAdapter?.setListener(object : HorizontalStoryAdapter.Listener { - override fun onOptionClick(item: Story, pos: Int) { + override fun onStoryClick(item: Story, pos: Int) { openHistoryVideo( Settings.get().accounts().current, ArrayList( presenter?.stories ?: emptyList() ), pos ) } + + override fun onStoryLongClick(item: Story, pos: Int): Boolean { + PlaceFactory.getLikesCopiesPlace( + Settings.get().accounts().current, + "stories_view", + item.ownerId, + item.id, + null + ).tryOpenWith(requireActivity()) + return true + } }) headerStoryRecyclerView.adapter = mStoryAdapter mWallAdapter = WallAdapter(requireActivity(), mutableListOf(), this, this) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/IAttachmentsPlacesView.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/IAttachmentsPlacesView.kt index df21a0539..819aadef7 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/IAttachmentsPlacesView.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/IAttachmentsPlacesView.kt @@ -45,8 +45,8 @@ interface IAttachmentsPlacesView { fun openPoll(accountId: Long, apiPoll: Poll) fun openSearch(accountId: Long, @SearchContentType type: Int, criteria: BaseSearchCriteria?) fun openComments(accountId: Long, commented: Commented, focusToCommentId: Int?) - fun goToLikes(accountId: Long, type: String?, ownerId: Long, id: Int) - fun goToReposts(accountId: Long, type: String?, ownerId: Long, id: Int) + fun goToLikes(accountId: Long, type: String, ownerId: Long, id: Int) + fun goToReposts(accountId: Long, type: String, ownerId: Long, id: Int) fun repostPost(accountId: Long, post: Post) fun openStory(accountId: Long, story: Story) fun openAudioPlaylist(accountId: Long, playlist: AudioPlaylist) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/PlaceSupportMvpFragment.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/PlaceSupportMvpFragment.kt index 11c885e27..ff0287afa 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/PlaceSupportMvpFragment.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/PlaceSupportMvpFragment.kt @@ -324,7 +324,7 @@ abstract class PlaceSupportMvpFragment

, V> : BaseMv .tryOpenWith(requireActivity()) } - override fun goToLikes(accountId: Long, type: String?, ownerId: Long, id: Int) { + override fun goToLikes(accountId: Long, type: String, ownerId: Long, id: Int) { PlaceFactory.getLikesCopiesPlace( accountId, type, @@ -335,7 +335,7 @@ abstract class PlaceSupportMvpFragment

, V> : BaseMv .tryOpenWith(requireActivity()) } - override fun goToReposts(accountId: Long, type: String?, ownerId: Long, id: Int) { + override fun goToReposts(accountId: Long, type: String, ownerId: Long, id: Int) { PlaceFactory.getLikesCopiesPlace( accountId, type, diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/PlaceSupportPresenter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/PlaceSupportPresenter.kt index bc16d233b..f1b8d5687 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/PlaceSupportPresenter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/PlaceSupportPresenter.kt @@ -155,7 +155,7 @@ abstract class PlaceSupportPresenter(accountId: Long, savedInstanceState: Bun } } - fun fireCopiesLikesClick(type: String?, ownerId: Long, itemId: Int, filter: String?) { + fun fireCopiesLikesClick(type: String, ownerId: Long, itemId: Int, filter: String?) { if (ILikesInteractor.FILTER_LIKES == filter) { view?.goToLikes(accountId, type, ownerId, itemId) } else if (ILikesInteractor.FILTER_COPIES == filter) { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/horizontal/HorizontalStoryAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/horizontal/HorizontalStoryAdapter.kt index d1e28d918..57732b383 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/horizontal/HorizontalStoryAdapter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/base/horizontal/HorizontalStoryAdapter.kt @@ -61,7 +61,13 @@ class HorizontalStoryAdapter(data: MutableList) : Constants.PICASSO_TAG ) } - viewHolder.itemView.setOnClickListener { listener?.onOptionClick(item, position) } + viewHolder.itemView.setOnClickListener { listener?.onStoryClick(item, position) } + viewHolder.itemView.setOnLongClickListener { + listener?.onStoryLongClick( + item, + position + ) == true + } } override fun viewHolder(view: View, type: Int): Holder { @@ -77,7 +83,8 @@ class HorizontalStoryAdapter(data: MutableList) : } interface Listener { - fun onOptionClick(item: Story, pos: Int) + fun onStoryClick(item: Story, pos: Int) + fun onStoryLongClick(item: Story, pos: Int): Boolean } class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/FeedFragment.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/FeedFragment.kt index 49c99f7fb..376fee010 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/FeedFragment.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/FeedFragment.kt @@ -298,7 +298,7 @@ class FeedFragment : PlaceSupportMvpFragment(), IFeedV return true } - override fun goToLikes(accountId: Long, type: String?, ownerId: Long, id: Int) { + override fun goToLikes(accountId: Long, type: String, ownerId: Long, id: Int) { getLikesCopiesPlace( accountId, type, @@ -308,7 +308,7 @@ class FeedFragment : PlaceSupportMvpFragment(), IFeedV ).tryOpenWith(requireActivity()) } - override fun goToReposts(accountId: Long, type: String?, ownerId: Long, id: Int) { + override fun goToReposts(accountId: Long, type: String, ownerId: Long, id: Int) { getLikesCopiesPlace( accountId, type, diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/FeedPresenter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/FeedPresenter.kt index f32b853e4..690e259c2 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/FeedPresenter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/FeedPresenter.kt @@ -398,7 +398,7 @@ class FeedPresenter(accountId: Long, savedInstanceState: Bundle?) : fun fireNewsShareLongClick(news: News) { view?.goToReposts( accountId, - news.type, + news.type.orEmpty(), news.sourceId, news.postId ) @@ -407,7 +407,7 @@ class FeedPresenter(accountId: Long, savedInstanceState: Bundle?) : fun fireNewsLikeLongClick(news: News) { view?.goToLikes( accountId, - news.type, + news.type.orEmpty(), news.sourceId, news.postId ) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/IFeedView.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/IFeedView.kt index 07bf59a85..3475c3abf 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/IFeedView.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feed/IFeedView.kt @@ -18,8 +18,8 @@ interface IFeedView : IAttachmentsPlacesView, IMvpView, IErrorView { fun showRefreshing(refreshing: Boolean) fun scrollFeedSourcesToPosition(position: Int) fun scrollTo(pos: Int) - override fun goToLikes(accountId: Long, type: String?, ownerId: Long, id: Int) - override fun goToReposts(accountId: Long, type: String?, ownerId: Long, id: Int) + override fun goToLikes(accountId: Long, type: String, ownerId: Long, id: Int) + override fun goToReposts(accountId: Long, type: String, ownerId: Long, id: Int) fun goToPostComments(accountId: Long, postId: Int, ownerId: Long) fun showSuccessToast() fun askToReload() diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feedbackvkofficial/FeedbackVKOfficialAdapter.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feedbackvkofficial/FeedbackVKOfficialAdapter.kt index 0611c7fb7..0e711020a 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feedbackvkofficial/FeedbackVKOfficialAdapter.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/feedbackvkofficial/FeedbackVKOfficialAdapter.kt @@ -63,7 +63,11 @@ class FeedbackVKOfficialAdapter( if (IconRes == null && Page.iconURL == null) { if (isSmall) { holder.small.visibility = View.VISIBLE - holder.small.setImageResource(R.drawable.client_round) + holder.small.setImageResource( + if (Settings.get() + .other().isRunes_show + ) R.drawable.client_round else R.drawable.client_round_vk + ) Utils.setColorFilter( holder.small, CurrentTheme.getColorPrimary( context @@ -71,7 +75,11 @@ class FeedbackVKOfficialAdapter( ) } else { holder.small.visibility = View.INVISIBLE - holder.avatar.setImageResource(R.drawable.client_round) + holder.avatar.setImageResource( + if (Settings.get() + .other().isRunes_show + ) R.drawable.client_round else R.drawable.client_round_vk + ) Utils.setColorFilter( holder.avatar, CurrentTheme.getColorPrimary( context diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/likes/LikesFragment.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/likes/LikesFragment.kt index cd48c2026..c88a694bb 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/likes/LikesFragment.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/likes/LikesFragment.kt @@ -14,7 +14,11 @@ class LikesFragment : AbsOwnersListFragment(accountId, savedInstanceState) { private val likesInteractor: ILikesInteractor = InteractorFactory.createLikesInteractor() @@ -29,22 +29,39 @@ class LikesListPresenter( loadingNow = true //this.loadingOffset = offset; resolveRefreshingView() - netDisposable.add(likesInteractor.getLikes( - accountId, - type, - ownerId, - itemId, - filter, - 50, - offset - ) - .fromIOToMain() - .subscribe({ owners -> - onDataReceived( - offset, - owners - ) - }) { t -> onDataGetError(t) }) + if (type == "stories_view") { + netDisposable.add(likesInteractor.getStoriesViewers( + accountId, + ownerId, + itemId, + 50, + offset + ) + .fromIOToMain() + .subscribe({ owners -> + onDataReceived( + offset, + owners + ) + }) { t -> onDataGetError(t) }) + } else { + netDisposable.add(likesInteractor.getLikes( + accountId, + type, + ownerId, + itemId, + filter, + 50, + offset + ) + .fromIOToMain() + .subscribe({ owners -> + onDataReceived( + offset, + owners + ) + }) { t -> onDataGetError(t) }) + } } private fun onDataGetError(t: Throwable) { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/videopreview/VideoPreviewFragment.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/videopreview/VideoPreviewFragment.kt index 901e3c424..7f253229f 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/videopreview/VideoPreviewFragment.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/fragment/videopreview/VideoPreviewFragment.kt @@ -458,8 +458,8 @@ class VideoPreviewFragment : BaseMvpFragment()) { if (video.externalLink?.contains("youtube") == true) { when { - AppPrefs.isVancedYoutubeInstalled(requireActivity()) -> { - playWithYoutubeVanced(video) + AppPrefs.isReVancedYoutubeInstalled(requireActivity()) -> { + playWithYoutubeReVanced(video) } AppPrefs.isNewPipeInstalled(requireActivity()) -> { @@ -660,7 +660,7 @@ class VideoPreviewFragment : BaseMvpFragment playWithYoutube(video) - Menu.YOUTUBE_VANCED -> playWithYoutubeVanced(video) + Menu.YOUTUBE_VANCED -> playWithYoutubeReVanced(video) Menu.COUB -> playWithCoub(video) Menu.PLAY_ANOTHER_SOFT -> video.externalLink?.let { playWithExternalSoftware(it) } Menu.PLAY_BROWSER -> video.player?.let { playWithExternalSoftware(it) } @@ -812,14 +812,14 @@ class VideoPreviewFragment : BaseMvpFragment? = null + fun isCoubInstalled(context: Context): Boolean { return isPackageIntalled(context, "com.coub.android") } @@ -17,8 +19,21 @@ object AppPrefs { return isPackageIntalled(context, "com.google.android.youtube") } - fun isVancedYoutubeInstalled(context: Context): Boolean { - return isPackageIntalled(context, "app.revanced.android.youtube") + fun isReVancedYoutubeInstalled(context: Context): Boolean { + if (isPackageIntalled(context, "app.revanced.android.youtube")) { + revanced = Pair( + "app.revanced.android.youtube", + "com.google.android.apps.youtube.app.application.Shell\$UrlActivity" + ) + return true + } else if (isPackageIntalled(context, "app.rvx.android.youtube")) { + revanced = Pair( + "app.rvx.android.youtube", + "com.google.android.apps.youtube.app.application.Shell\$UrlActivity" + ) + return true + } + return false } @Suppress("deprecation") diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/ISettings.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/ISettings.kt index 5c0ff18e3..6cd6570c4 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/ISettings.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/ISettings.kt @@ -223,6 +223,7 @@ interface ISettings { val isSnow_mode: Boolean val photoRoundMode: Int val fontSize: Int + val fontOnlyForChats: Boolean val isLoad_history_notif: Boolean val isDont_write: Boolean val isOver_ten_attach: Boolean diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/MainSettings.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/MainSettings.kt index 27ff25200..d609dfb20 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/MainSettings.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/MainSettings.kt @@ -145,11 +145,10 @@ internal class MainSettings(context: Context) : IMainSettings { 0 } override val fontSize: Int - get() = try { - defaultPreferences.getString("font_size", "0")?.trim { it <= ' ' }?.toInt() ?: 0 - } catch (e: Exception) { - 0 - } + get() = defaultPreferences.getInt("font_size_int", 0) + + override val fontOnlyForChats: Boolean + get() = defaultPreferences.getBoolean("font_only_for_chats", false) override fun setPrefDisplayImageSize(@PhotoSize size: Int) { defaultPreferences diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/SecuritySettings.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/SecuritySettings.kt index e029c5864..e13187317 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/SecuritySettings.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/SecuritySettings.kt @@ -208,7 +208,7 @@ class SecuritySettings internal constructor(context: Context) : ISecuritySetting private const val KEY_HIDDEN_PEERS = "hidden_peers" private const val pinHistoryDepth = 3 - internal fun extractPinEnterHistrory(preferences: SharedPreferences): ArrayList { + internal fun extractPinEnterHistory(preferences: SharedPreferences): ArrayList { val set = preferences.getStringSet(KEY_PIN_ENTER_HISTORY, null) val result = ArrayList(safeCountOf(set)) if (set != null) { @@ -235,9 +235,9 @@ class SecuritySettings internal constructor(context: Context) : ISecuritySetting init { mPinHash = mPrefs.getString(KEY_PIN_HASH, null) - mPinEnterHistory = extractPinEnterHistrory(mPrefs) + mPinEnterHistory = extractPinEnterHistory(mPrefs) mKeyEncryptionPolicyAccepted = mPrefs.getBoolean(KEY_ENCRYPTION_POLICY_ACCEPTED, false) hiddenPeers = Collections.synchronizedSet(HashSet(1)) reloadHiddenDialogSettings() } -} \ No newline at end of file +} diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/backup/SettingsBackup.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/backup/SettingsBackup.kt index ab89197ae..c894a6cbe 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/backup/SettingsBackup.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/settings/backup/SettingsBackup.kt @@ -40,7 +40,8 @@ class SettingsBackup { var player_cover_transform: String? = null var pref_display_photo_size: Int? = null var photo_rounded_view: String? = null - var font_size: String? = null + var font_size_int: Int? = null + var font_only_for_chats: Boolean? = null var is_open_url_internal: String? = null var webview_night_mode: Boolean? = null var load_history_notif: Boolean? = null diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/Utils.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/Utils.kt index 86211bfe4..3671e60c3 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/Utils.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/Utils.kt @@ -915,17 +915,11 @@ object Utils { } fun setTint(view: ImageView?, @ColorInt color: Int) { - if (view == null) { - return - } - view.imageTintList = ColorStateList.valueOf(color) + view?.imageTintList = ColorStateList.valueOf(color) } fun setBackgroundTint(view: View?, @ColorInt color: Int) { - if (view == null) { - return - } - view.backgroundTintList = ColorStateList.valueOf(color) + view?.backgroundTintList = ColorStateList.valueOf(color) } @Suppress("DEPRECATION") @@ -1440,7 +1434,7 @@ object Utils { } } - fun updateActivityContext(base: Context): Context { + fun updateActivityContext(base: Context, isChatActivity: Boolean = false): Context { if (getSystemLocale(base.resources.configuration) != null && getSystemLocale(base.resources.configuration)?.language.nonNullNoEmpty()) { Constants.DEVICE_COUNTRY_CODE = getSystemLocale(base.resources.configuration)?.language?.lowercase(Locale.getDefault()) @@ -1453,7 +1447,7 @@ object Utils { val locale = getLocaleSettings(lang) updateDateLang(locale) updateDateLang() - return if (size == 0) { + return if (size == 0 || Settings.get().main().fontOnlyForChats && !isChatActivity) { if (lang == Lang.DEFAULT) { base } else { @@ -1465,7 +1459,7 @@ object Utils { } else { val res = base.resources val config = Configuration(res.configuration) - config.fontScale = res.configuration.fontScale + 0.15f * size + config.fontScale = res.configuration.fontScale + 0.05f * size if (lang != Lang.DEFAULT) { setSystemLocaleLegacy(config, getLocaleSettings(lang)) } diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/JsonElementSerializers.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/JsonElementSerializers.kt index 2c9333d87..08e3ba12c 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/JsonElementSerializers.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/JsonElementSerializers.kt @@ -15,7 +15,7 @@ import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonElement]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonElement]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). * Currently, this hierarchy has no guarantees on descriptor content. * @@ -26,7 +26,6 @@ import kotlinx.serialization.encoding.Encoder * assertEquals(JsonObject(mapOf("key" to JsonLiteral(1.0))), literal) * ``` */ -@Serializer(forClass = JsonElement::class) @PublishedApi internal object JsonElementSerializer : KSerializer { @OptIn(InternalSerializationApi::class) @@ -59,10 +58,9 @@ internal object JsonElementSerializer : KSerializer { } /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonPrimitive]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonPrimitive]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). */ -@Serializer(forClass = JsonPrimitive::class) @PublishedApi internal object JsonPrimitiveSerializer : KSerializer { @OptIn(InternalSerializationApi::class) @@ -93,10 +91,9 @@ internal object JsonPrimitiveSerializer : KSerializer { } /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonNull]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonNull]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). */ -@Serializer(forClass = JsonNull::class) @PublishedApi internal object JsonNullSerializer : KSerializer { // technically, JsonNull is an object, but it does not call beginStructure/endStructure at all @@ -166,10 +163,9 @@ private object JsonLiteralSerializer : KSerializer { } /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonObject]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonObject]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). */ -@Serializer(forClass = JsonObject::class) @PublishedApi internal object JsonObjectSerializer : KSerializer { @@ -197,10 +193,9 @@ internal object JsonObjectSerializer : KSerializer { } /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonArray]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonArray]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). */ -@Serializer(forClass = JsonArray::class) @PublishedApi internal object JsonArraySerializer : KSerializer { @@ -223,11 +218,11 @@ internal object JsonArraySerializer : KSerializer { } } -internal fun verify(encoder: Encoder) { +private fun verify(encoder: Encoder) { encoder.asJsonEncoder() } -internal fun verify(decoder: Decoder) { +private fun verify(decoder: Decoder) { decoder.asJsonDecoder() } @@ -249,7 +244,7 @@ internal fun Encoder.asJsonEncoder() = this as? JsonEncoder * Used to resolve cyclic dependencies between recursive serializable structures. */ @OptIn(ExperimentalSerializationApi::class) -internal fun defer(deferred: () -> SerialDescriptor): SerialDescriptor = object : SerialDescriptor { +private fun defer(deferred: () -> SerialDescriptor): SerialDescriptor = object : SerialDescriptor { private val original: SerialDescriptor by lazy(deferred) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/JsonNamesMap.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/JsonNamesMap.kt index 3648be28f..d041e091f 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/JsonNamesMap.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/JsonNamesMap.kt @@ -108,12 +108,16 @@ internal fun SerialDescriptor.getJsonNameIndexOrThrow( @OptIn(ExperimentalSerializationApi::class) internal inline fun Json.tryCoerceValue( elementDescriptor: SerialDescriptor, - peekNull: () -> Boolean, + peekNull: (consume: Boolean) -> Boolean, peekString: () -> String?, onEnumCoercing: () -> Unit = {} ): Boolean { - if (!elementDescriptor.isNullable && peekNull()) return true + if (!elementDescriptor.isNullable && peekNull(true)) return true if (elementDescriptor.kind == SerialKind.ENUM) { + if (elementDescriptor.isNullable && peekNull(false)) { + return false + } + val enumValue = peekString() ?: return false // if value is not a string, decodeEnum() will throw correct exception val enumIndex = elementDescriptor.getJsonNameIndex(this, enumValue) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/StreamingJsonDecoder.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/StreamingJsonDecoder.kt index 6b2029264..38b3967d2 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/StreamingJsonDecoder.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/StreamingJsonDecoder.kt @@ -17,6 +17,7 @@ import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.MissingFieldException import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.AbstractDecoder +import kotlinx.serialization.encoding.ChunkedDecoder import kotlinx.serialization.encoding.CompositeDecoder import kotlinx.serialization.encoding.CompositeDecoder.Companion.DECODE_DONE import kotlinx.serialization.encoding.CompositeDecoder.Companion.UNKNOWN_NAME @@ -34,7 +35,7 @@ internal open class StreamingJsonDecoder( @JvmField internal val lexer: AbstractJsonLexer, descriptor: SerialDescriptor, private var discriminatorHolder: DiscriminatorHolder? -) : JsonDecoder, AbstractDecoder() { +) : JsonDecoder, ChunkedDecoder, AbstractDecoder() { // A mutable reference to the discriminator that have to be skipped when in optimistic phase // of polymorphic serialization, see `decodeSerializableValue` @@ -93,7 +94,6 @@ internal open class StreamingJsonDecoder( } discriminatorHolder = DiscriminatorHolder(discriminator) - @Suppress("UNCHECKED_CAST") return actualSerializer.deserialize(this) as T @@ -149,7 +149,7 @@ internal open class StreamingJsonDecoder( } override fun decodeNotNullMark(): Boolean { - return !(elementMarker?.isUnmarkedNull ?: false) && lexer.tryConsumeNotNull() + return !(elementMarker?.isUnmarkedNull ?: false) && !lexer.tryConsumeNull() } override fun decodeNull(): Nothing? { @@ -225,7 +225,7 @@ internal open class StreamingJsonDecoder( private fun coerceInputValue(descriptor: SerialDescriptor, index: Int): Boolean = json.tryCoerceValue( descriptor.getElementDescriptor(index), - { !lexer.tryConsumeNotNull() }, + { lexer.tryConsumeNull(it) }, { lexer.peekString(configuration.isLenient) }, { lexer.consumeString() /* skip unknown enum string*/ } ) @@ -362,6 +362,10 @@ internal open class StreamingJsonDecoder( } } + override fun decodeStringChunked(consumeChunk: (chunk: String) -> Unit) { + lexer.consumeStringChunked(configuration.isLenient, consumeChunk) + } + override fun decodeInline(descriptor: SerialDescriptor): Decoder = if (descriptor.isUnsignedNumber) JsonDecoderForUnsignedTypes(lexer, json) else super.decodeInline(descriptor) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/lexer/AbstractJsonLexer.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/lexer/AbstractJsonLexer.kt index 8fedd4514..e349d97e7 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/lexer/AbstractJsonLexer.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/lexer/AbstractJsonLexer.kt @@ -251,25 +251,28 @@ internal abstract class AbstractJsonLexer { /** * Tries to consume `null` token from input. - * Returns `true` if the next 4 chars in input are not `null`, - * `false` otherwise and consumes it. + * Returns `false` if the next 4 chars in input are not `null`, + * `true` otherwise and consumes it if [doConsume] is `true`. */ - fun tryConsumeNotNull(): Boolean { + fun tryConsumeNull(doConsume: Boolean = true): Boolean { var current = skipWhitespaces() current = prefetchOrEof(current) // Cannot consume null due to EOF, maybe something else val len = source.length - current - if (len < 4 || current == -1) return true + if (len < 4 || current == -1) return false for (i in 0..3) { - if (NULL[i] != source[current + i]) return true + if (NULL[i] != source[current + i]) return false } /* * If we're in lenient mode, this might be the string with 'null' prefix, * distinguish it from 'null' */ - if (len > 4 && charToTokenClass(source[current + 4]) == TC_OTHER) return true - currentPosition = current + 4 - return false + if (len > 4 && charToTokenClass(source[current + 4]) == TC_OTHER) return false + + if (doConsume) { + currentPosition = current + 4 + } + return true } open fun skipWhitespaces(): Int { @@ -314,6 +317,66 @@ internal abstract class AbstractJsonLexer { */ abstract fun consumeKeyString(): String + private fun insideString(isLenient: Boolean, char: Char): Boolean = if (isLenient) { + charToTokenClass(char) == TC_OTHER + } else { + char != STRING + } + + open fun consumeStringChunked( + isLenient: Boolean, + consumeChunk: (stringChunk: String) -> Unit + ) { // open to allow simpler implementations (i.e. StringJsonLexer) + val nextToken = peekNextToken() + if (isLenient && nextToken != TC_OTHER) return // noting to consume + + if (!isLenient) { + consumeNextToken(STRING) + } + var currentPosition = this.currentPosition + var lastPosition = currentPosition + var char = source[currentPosition] // Avoid two range checks visible in the profiler + var usedAppend = false + while (insideString(isLenient, char)) { + if (!isLenient && char == STRING_ESC) { // handle escaping only in non-lenient mode + usedAppend = true + currentPosition = prefetchOrEof(appendEscape(lastPosition, currentPosition)) + lastPosition = currentPosition + } else { + currentPosition++ + } + if (currentPosition >= source.length) { + // end of chunk + writeRange(lastPosition, currentPosition, usedAppend, consumeChunk) + usedAppend = false + currentPosition = prefetchOrEof(currentPosition) + if (currentPosition == -1) + fail("EOF", currentPosition) + lastPosition = currentPosition + } + char = source[currentPosition] + } + writeRange(lastPosition, currentPosition, usedAppend, consumeChunk) + this.currentPosition = currentPosition + if (!isLenient) { + consumeNextToken(STRING) + } + } + + private fun writeRange( + fromIndex: Int, + toIndex: Int, + currentChunkHasEscape: Boolean, + consumeChunk: (stringChunk: String) -> Unit + ) { + if (currentChunkHasEscape) { + consumeChunk(decodedString(fromIndex, toIndex)) + } else { + consumeChunk(substring(fromIndex, toIndex)) + } + } + + fun consumeString(): String { if (peekedString != null) { return takePeeked() diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/lexer/StringJsonLexer.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/lexer/StringJsonLexer.kt index 97559e8bb..7af16e29d 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/lexer/StringJsonLexer.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/json/internal/lexer/StringJsonLexer.kt @@ -103,6 +103,14 @@ internal class StringJsonLexer(override val source: String) : AbstractJsonLexer( return source.substring(current, closingQuote) } + override fun consumeStringChunked( + isLenient: Boolean, + consumeChunk: (stringChunk: String) -> Unit + ) { + (if (isLenient) consumeStringLenient() else consumeString()).chunked(BATCH_SIZE) + .forEach(consumeChunk) + } + override fun consumeLeadingMatchingValue(keyToMatch: String, isLenient: Boolean): String? { val positionSnapshot = currentPosition try { diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/msgpack/MsgPackTreeReader.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/msgpack/MsgPackTreeReader.kt index 891709378..89f8a6a5e 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/msgpack/MsgPackTreeReader.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/msgpack/MsgPackTreeReader.kt @@ -32,7 +32,7 @@ internal class MsgPackTreeReader( .joinToNumber() type == MsgPackType.Array.ARRAY32 -> { - if (basicMsgPackDecoder.configuration.preventOverflows) { + if (basicMsgPackDecoder.getConfiguration().preventOverflows) { val number = basicMsgPackDecoder.dataBuffer.takeNext(4).joinToNumber() if (number !in Int.MIN_VALUE..Int.MAX_VALUE) { throw MsgPackSerializationException.overflowError(basicMsgPackDecoder.dataBuffer) @@ -64,7 +64,7 @@ internal class MsgPackTreeReader( .joinToNumber() type == MsgPackType.Map.MAP32 -> { - if (basicMsgPackDecoder.configuration.preventOverflows) { + if (basicMsgPackDecoder.getConfiguration().preventOverflows) { val number = basicMsgPackDecoder.dataBuffer.takeNext(4).joinToNumber() if (number !in Int.MIN_VALUE..Int.MAX_VALUE) { throw MsgPackSerializationException.overflowError(basicMsgPackDecoder.dataBuffer) diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/msgpack/internal/MsgPackDecoder.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/msgpack/internal/MsgPackDecoder.kt index 35bc5ffac..389a4281e 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/msgpack/internal/MsgPackDecoder.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/util/serializeble/msgpack/internal/MsgPackDecoder.kt @@ -22,26 +22,27 @@ interface MsgPackTypeDecoder { } internal class BasicMsgPackDecoder( - val configuration: MsgPackConfiguration, + private val configuration: MsgPackConfiguration, override val serializersModule: SerializersModule, val dataBuffer: MsgPackDataInputBuffer, private val msgUnpacker: MsgUnpacker = BasicMsgUnpacker(dataBuffer), val inlineDecoders: Map Decoder> = mapOf() ) : AbstractDecoder(), MsgPackTypeDecoder { fun decodeMsgPackElement(): JsonElement = MsgPackTreeReader(this).read() + fun getConfiguration(): MsgPackConfiguration { + return configuration + } - val depthStack: ArrayDeque = ArrayDeque() - - override fun decodeElementIndex(descriptor: SerialDescriptor): Int { + internal fun decodeElementIndexInternal(descriptor: SerialDescriptor): Int { if (descriptor.kind in arrayOf(StructureKind.CLASS, StructureKind.OBJECT)) { val next = dataBuffer.peekSafely() if (next != null && MsgPackType.String.isString(next)) { val fieldName = kotlin.runCatching { decodeString() }.getOrNull() ?: return CompositeDecoder.UNKNOWN_NAME val index = descriptor.getElementIndex(fieldName) - return if (index == CompositeDecoder.UNKNOWN_NAME && configuration.ignoreUnknownKeys && depthStack.isEmpty()) { + return if (index == CompositeDecoder.UNKNOWN_NAME && configuration.ignoreUnknownKeys) { MsgPackNullableDynamicSerializer.deserialize(this) - decodeElementIndex(descriptor) + index } else { index } @@ -52,6 +53,14 @@ internal class BasicMsgPackDecoder( return 0 } + override fun decodeElementIndex(descriptor: SerialDescriptor): Int { + val result = decodeElementIndexInternal(descriptor) + if (result == CompositeDecoder.UNKNOWN_NAME && configuration.ignoreUnknownKeys) { + return decodeElementIndex(descriptor) + } + return result + } + override fun decodeSequentially(): Boolean = true override fun decodeNotNullMark(): Boolean { @@ -222,19 +231,12 @@ internal class BasicMsgPackDecoder( return ExtensionTypeDecoder(this) } - depthStack.addFirst(Unit) - // Handle extension types as arrays val size = decodeCollectionSize(descriptor) - return ClassMsgPackDecoder(this, size) + return ClassMsgPackDecoder(this, configuration, size) } return this } - override fun endStructure(descriptor: SerialDescriptor) { - super.endStructure(descriptor) - depthStack.removeFirstOrNull() - } - override fun peekNextType(): Byte { return dataBuffer.peek() } @@ -249,42 +251,19 @@ internal class MsgPackDecoder( internal class ClassMsgPackDecoder( private val basicMsgPackDecoder: BasicMsgPackDecoder, + private val configuration: MsgPackConfiguration, private val size: Int ) : Decoder by basicMsgPackDecoder, CompositeDecoder by basicMsgPackDecoder, MsgPackTypeDecoder by basicMsgPackDecoder { override val serializersModule: SerializersModule = basicMsgPackDecoder.serializersModule - private fun decodeElemIndex(descriptor: SerialDescriptor, size: Int): Int { - if (descriptor.kind in arrayOf(StructureKind.CLASS, StructureKind.OBJECT)) { - val next = basicMsgPackDecoder.dataBuffer.peekSafely() - if (next != null && MsgPackType.String.isString(next)) { - val fieldName = kotlin.runCatching { decodeString() }.getOrNull() - ?: return CompositeDecoder.UNKNOWN_NAME - val index = descriptor.getElementIndex(fieldName) - return if (index == CompositeDecoder.UNKNOWN_NAME && basicMsgPackDecoder.configuration.ignoreUnknownKeys && basicMsgPackDecoder.depthStack.isEmpty()) { - MsgPackNullableDynamicSerializer.deserialize(this) - decodedElements++ - if (decodedElements >= size) CompositeDecoder.DECODE_DONE else decodeElemIndex( - descriptor, - size - ) - } else { - index - } - } else { - return CompositeDecoder.DECODE_DONE - } - } - return 0 - } private var decodedElements = 0 override fun decodeElementIndex(descriptor: SerialDescriptor): Int { if (decodedElements >= size) return CompositeDecoder.DECODE_DONE - val result = decodeElemIndex(descriptor, size) + val result = basicMsgPackDecoder.decodeElementIndexInternal(descriptor) if (result != CompositeDecoder.DECODE_DONE) decodedElements++ - return if (result == CompositeDecoder.UNKNOWN_NAME) { - MsgPackNullableDynamicSerializer.deserialize(this) + return if (result == CompositeDecoder.UNKNOWN_NAME && configuration.ignoreUnknownKeys) { decodeElementIndex(descriptor) } else { result diff --git a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/emoji/EmojiconTextView.kt b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/emoji/EmojiconTextView.kt index d9f1ab942..d61c29cca 100644 --- a/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/emoji/EmojiconTextView.kt +++ b/app_fenrir/src/main/kotlin/dev/ragnarok/fenrir/view/emoji/EmojiconTextView.kt @@ -162,8 +162,8 @@ class EmojiconTextView @JvmOverloads constructor(context: Context, attrs: Attrib override fun onClick(widget: View) { if (URL_YOUTUBE_PATTERN.matcher(url).find()) { val menus = ModalBottomSheetDialogFragment.Builder() - val hasVanced = AppPrefs.isVancedYoutubeInstalled(context) - if (hasVanced) { + val hasReVanced = AppPrefs.isReVancedYoutubeInstalled(context) + if (hasReVanced) { menus.add( OptionRequest( 1, @@ -181,7 +181,7 @@ class EmojiconTextView @JvmOverloads constructor(context: Context, attrs: Attrib true ) ) - if (!hasVanced && AppPrefs.isYoutubeInstalled(context)) { + if (!hasReVanced && AppPrefs.isYoutubeInstalled(context)) { menus.add( OptionRequest( 3, @@ -216,8 +216,8 @@ class EmojiconTextView @JvmOverloads constructor(context: Context, attrs: Attrib intent.data = Uri.parse(url) intent.action = Intent.ACTION_VIEW intent.component = ComponentName( - "app.revanced.android.youtube", - "com.google.android.apps.youtube.app.application.Shell\$UrlActivity" + AppPrefs.revanced?.first.orEmpty(), + AppPrefs.revanced?.second.orEmpty() ) context.startActivity(intent) } diff --git a/app_fenrir/src/main/res/drawable/client_round.xml b/app_fenrir/src/main/res/drawable/client_round.xml deleted file mode 100644 index 871aeb0cd..000000000 --- a/app_fenrir/src/main/res/drawable/client_round.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - diff --git a/app_fenrir/src/main/res/drawable/client_round_vk.xml b/app_fenrir/src/main/res/drawable/client_round_vk.xml new file mode 100644 index 000000000..bcdab35eb --- /dev/null +++ b/app_fenrir/src/main/res/drawable/client_round_vk.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/app_fenrir/src/main/res/layout/content_post.xml b/app_fenrir/src/main/res/layout/content_post.xml index 812d8ca59..5db141ad1 100644 --- a/app_fenrir/src/main/res/layout/content_post.xml +++ b/app_fenrir/src/main/res/layout/content_post.xml @@ -62,7 +62,7 @@ android:layout_marginTop="4dp" android:layout_marginBottom="4dp" android:drawablePadding="4dp" - android:text="@string/visible_only_dons" + android:text="@string/available_only_dons" android:textAppearance="@style/TextAppearance.Material3.TitleMedium" android:visibility="gone" app:drawableStartCompat="@drawable/donate" diff --git a/app_fenrir/src/main/res/layout/fragment_post.xml b/app_fenrir/src/main/res/layout/fragment_post.xml index b4de79f81..0cecfc3f5 100644 --- a/app_fenrir/src/main/res/layout/fragment_post.xml +++ b/app_fenrir/src/main/res/layout/fragment_post.xml @@ -107,7 +107,7 @@ android:layout_marginTop="4dp" android:layout_marginBottom="4dp" android:drawablePadding="4dp" - android:text="@string/visible_only_dons" + android:text="@string/available_only_dons" android:textAppearance="@style/TextAppearance.Material3.TitleMedium" android:visibility="gone" app:drawableStartCompat="@drawable/donate" diff --git a/app_fenrir/src/main/res/layout/item_feed.xml b/app_fenrir/src/main/res/layout/item_feed.xml index 3cb58d4e8..c886c443b 100644 --- a/app_fenrir/src/main/res/layout/item_feed.xml +++ b/app_fenrir/src/main/res/layout/item_feed.xml @@ -122,7 +122,7 @@ android:layout_marginTop="8dp" android:layout_marginBottom="4dp" android:drawablePadding="4dp" - android:text="@string/visible_only_dons" + android:text="@string/available_only_dons" android:textAppearance="@style/TextAppearance.Material3.TitleMedium" android:visibility="gone" app:drawableStartCompat="@drawable/donate" diff --git a/app_fenrir/src/main/res/values-be/strings.xml b/app_fenrir/src/main/res/values-be/strings.xml index 1af36f2d8..e52f4fe50 100644 --- a/app_fenrir/src/main/res/values-be/strings.xml +++ b/app_fenrir/src/main/res/values-be/strings.xml @@ -47,14 +47,6 @@ Не скругляць - - Па змаўчанні - Маленькі - Сярэдні - Вялікі - Вялізны - - Адключыць Абнаўляць @@ -1203,7 +1195,7 @@ Бітрэйт: %1$d kbs, Памер: %2$s Перавышаны час чакання запыту Няма падключэння да сеткі - SMS-код + Код из SMS Проксі Налады Пароль @@ -1717,5 +1709,7 @@ Фатаграфіі на сцяне Заблакаваць падпісчыка? Рэжым захавацца на сесію Токен абмену - Відаць толькі донам! + Даступна толькі донам! + Шрыфт толькі чатам + Прагляды \ No newline at end of file diff --git a/app_fenrir/src/main/res/values-ru/strings.xml b/app_fenrir/src/main/res/values-ru/strings.xml index a0e69104c..bc1f3c96b 100644 --- a/app_fenrir/src/main/res/values-ru/strings.xml +++ b/app_fenrir/src/main/res/values-ru/strings.xml @@ -47,14 +47,6 @@ Не скруглять - - По умолчанию - Маленький - Средний - Большой - Огромный - - Отключить Обновлять @@ -384,7 +376,7 @@ Недопустимый идентификатор альбома Недопустимый сервер Неверный хэш - Неверный timestamp + Неверная отметка времени Невозможно добавить в друзья самого себя Невозможно добавить в друзья пользователя, который занес Вас в свой черный список Невозможно добавить в друзья пользователя, который занесен в Ваш черный список @@ -1205,7 +1197,7 @@ Битрейт: %1$d kbs, Размер: %2$s Превышено время ожидание запроса Нет подключения к сети - SMS-код + Код из SMS Прокси Настройки Пароль @@ -1719,5 +1711,7 @@ Фотографии на стене Заблокировать подписчика? Режим сохраниться на сессию Токен обмена - Видно только донам! + Доступно только донам! + Шрифт только чатам + Просмотры \ No newline at end of file diff --git a/app_fenrir/src/main/res/values/strings.xml b/app_fenrir/src/main/res/values/strings.xml index 65e60202a..d66cdec2d 100644 --- a/app_fenrir/src/main/res/values/strings.xml +++ b/app_fenrir/src/main/res/values/strings.xml @@ -144,22 +144,6 @@ 2 - - Default - Small - Average - Large - Huge - - - - 0 - -1 - 1 - 2 - 3 - - Disable Update @@ -1438,7 +1422,7 @@ Bitrate: %1$d kbs, Size: %2$s Request timed out No network connection - SMS-code + Code from SMS Captcha Proxy Settings @@ -1964,5 +1948,7 @@ Photos on Wall Block a subscriber? Mode save per session Exchange Token - Visible only to dons! + Only available to dons! + Font only for chats + Views diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/fragment/PreferencesFragment.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/fragment/PreferencesFragment.kt index dc4f66349..267176dd1 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/fragment/PreferencesFragment.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/fragment/PreferencesFragment.kt @@ -371,17 +371,24 @@ class PreferencesFragment : AbsPreferencesFragment(), PreferencesAdapter.OnScree } } - singleChoice( - "font_size", - selItems(R.array.array_font_size_names, R.array.array_font_size_items), - parentFragmentManager - ) { - initialSelection = "0" + seekBar("font_size_int") { + min = -3 + max = 9 + default = 0 + step = 1 + showTickMarks = true titleRes = R.string.font_size - onSelectionChange { - requireActivity().recreate() + onSeek { + sleepDataDisposable.dispose() + sleepDataDisposable = Single.just(Any()) + .delay(1, TimeUnit.SECONDS) + .fromIOToMain() + .subscribe({ + requireActivity().recreate() + }, { RxUtils.dummy() }) } } + switch("use_internal_downloader") { defaultValue = true summaryRes = R.string.use_internal_downloader_summary diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/MainSettings.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/MainSettings.kt index 167b128f0..8d88d26a8 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/MainSettings.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/MainSettings.kt @@ -21,11 +21,7 @@ internal class MainSettings(context: Context) : IMainSettings { private val localServerPublisher: PublishSubject = PublishSubject.create() override fun getFontSize(): Int { - return try { - getPreferences(app).getString("font_size", "0")!!.trim().toInt() - } catch (e: Exception) { - 0 - } + return getPreferences(app).getInt("font_size_int", 0) } override val isValidate_tls: Boolean diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/SecuritySettings.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/SecuritySettings.kt index b7127c4f1..f391b4610 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/SecuritySettings.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/SecuritySettings.kt @@ -97,7 +97,7 @@ class SecuritySettings internal constructor(context: Context) : ISecuritySetting const val KEY_USE_PIN_FOR_ENTRANCE = "use_pin_for_entrance" private const val pinHistoryDepth = 3 - internal fun extractPinEnterHistrory(preferences: SharedPreferences): ArrayList { + internal fun extractPinEnterHistory(preferences: SharedPreferences): ArrayList { val set = preferences.getStringSet(KEY_PIN_ENTER_HISTORY, null) val result = ArrayList(safeCountOf(set)) if (set != null) { @@ -120,6 +120,6 @@ class SecuritySettings internal constructor(context: Context) : ISecuritySetting init { mPinHash = mPrefs.getString(KEY_PIN_HASH, null) - mPinEnterHistory = extractPinEnterHistrory(mPrefs) + mPinEnterHistory = extractPinEnterHistory(mPrefs) } -} \ No newline at end of file +} diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/backup/SettingsBackup.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/backup/SettingsBackup.kt index 7008ea21b..0844493c9 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/backup/SettingsBackup.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/settings/backup/SettingsBackup.kt @@ -23,7 +23,7 @@ class SettingsBackup { var theme_overlay: String? = null var language_ui: String? = null var delete_disabled: Boolean? = null - var font_size: String? = null + var font_size_int: Int? = null var local_media_server: String? = null var use_internal_downloader: Boolean? = null var video_controller_to_decor: Boolean? = null diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/Utils.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/Utils.kt index 441938294..d72d6a1fa 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/Utils.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/Utils.kt @@ -183,10 +183,7 @@ object Utils { } fun setBackgroundTint(view: View?, @ColorInt color: Int) { - if (view == null) { - return - } - view.backgroundTintList = ColorStateList.valueOf(color) + view?.backgroundTintList = ColorStateList.valueOf(color) } fun setColorFilter(view: ImageView?, @ColorInt color: Int) { @@ -412,7 +409,7 @@ object Utils { } else { val res = base.resources val config = Configuration(res.configuration) - config.fontScale = res.configuration.fontScale + 0.15f * size + config.fontScale = res.configuration.fontScale + 0.05f * size if (lang != Lang.DEFAULT) { setSystemLocaleLegacy(config, getLocaleSettings(lang)) } diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/JsonElementSerializers.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/JsonElementSerializers.kt index a0eccb989..f7d73880b 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/JsonElementSerializers.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/JsonElementSerializers.kt @@ -15,7 +15,7 @@ import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonElement]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonElement]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). * Currently, this hierarchy has no guarantees on descriptor content. * @@ -26,7 +26,6 @@ import kotlinx.serialization.encoding.Encoder * assertEquals(JsonObject(mapOf("key" to JsonLiteral(1.0))), literal) * ``` */ -@Serializer(forClass = JsonElement::class) @PublishedApi internal object JsonElementSerializer : KSerializer { @OptIn(InternalSerializationApi::class) @@ -59,10 +58,9 @@ internal object JsonElementSerializer : KSerializer { } /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonPrimitive]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonPrimitive]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). */ -@Serializer(forClass = JsonPrimitive::class) @PublishedApi internal object JsonPrimitiveSerializer : KSerializer { @OptIn(InternalSerializationApi::class) @@ -93,10 +91,9 @@ internal object JsonPrimitiveSerializer : KSerializer { } /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonNull]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonNull]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). */ -@Serializer(forClass = JsonNull::class) @PublishedApi internal object JsonNullSerializer : KSerializer { // technically, JsonNull is an object, but it does not call beginStructure/endStructure at all @@ -166,10 +163,9 @@ private object JsonLiteralSerializer : KSerializer { } /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonObject]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonObject]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). */ -@Serializer(forClass = JsonObject::class) @PublishedApi internal object JsonObjectSerializer : KSerializer { @@ -198,10 +194,9 @@ internal object JsonObjectSerializer : KSerializer { } /** - * External [Serializer] object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonArray]. + * Serializer object providing [SerializationStrategy] and [DeserializationStrategy] for [JsonArray]. * It can only be used by with [Json] format an its input ([JsonDecoder] and [JsonEncoder]). */ -@Serializer(forClass = JsonArray::class) @PublishedApi internal object JsonArraySerializer : KSerializer { @@ -225,11 +220,11 @@ internal object JsonArraySerializer : KSerializer { } } -internal fun verify(encoder: Encoder) { +private fun verify(encoder: Encoder) { encoder.asJsonEncoder() } -internal fun verify(decoder: Decoder) { +private fun verify(decoder: Decoder) { decoder.asJsonDecoder() } @@ -251,7 +246,7 @@ internal fun Encoder.asJsonEncoder() = this as? JsonEncoder * Used to resolve cyclic dependencies between recursive serializable structures. */ @OptIn(ExperimentalSerializationApi::class) -internal fun defer(deferred: () -> SerialDescriptor): SerialDescriptor = object : SerialDescriptor { +private fun defer(deferred: () -> SerialDescriptor): SerialDescriptor = object : SerialDescriptor { private val original: SerialDescriptor by lazy(deferred) diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/JsonNamesMap.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/JsonNamesMap.kt index 6f20dbb94..40d568dc4 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/JsonNamesMap.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/JsonNamesMap.kt @@ -108,12 +108,16 @@ internal fun SerialDescriptor.getJsonNameIndexOrThrow( @OptIn(ExperimentalSerializationApi::class) internal inline fun Json.tryCoerceValue( elementDescriptor: SerialDescriptor, - peekNull: () -> Boolean, + peekNull: (consume: Boolean) -> Boolean, peekString: () -> String?, onEnumCoercing: () -> Unit = {} ): Boolean { - if (!elementDescriptor.isNullable && peekNull()) return true + if (!elementDescriptor.isNullable && peekNull(true)) return true if (elementDescriptor.kind == SerialKind.ENUM) { + if (elementDescriptor.isNullable && peekNull(false)) { + return false + } + val enumValue = peekString() ?: return false // if value is not a string, decodeEnum() will throw correct exception val enumIndex = elementDescriptor.getJsonNameIndex(this, enumValue) diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/StreamingJsonDecoder.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/StreamingJsonDecoder.kt index a92069ed5..569467452 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/StreamingJsonDecoder.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/StreamingJsonDecoder.kt @@ -17,6 +17,7 @@ import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.MissingFieldException import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.AbstractDecoder +import kotlinx.serialization.encoding.ChunkedDecoder import kotlinx.serialization.encoding.CompositeDecoder import kotlinx.serialization.encoding.CompositeDecoder.Companion.DECODE_DONE import kotlinx.serialization.encoding.CompositeDecoder.Companion.UNKNOWN_NAME @@ -34,7 +35,7 @@ internal open class StreamingJsonDecoder( @JvmField internal val lexer: AbstractJsonLexer, descriptor: SerialDescriptor, private var discriminatorHolder: DiscriminatorHolder? -) : JsonDecoder, AbstractDecoder() { +) : JsonDecoder, ChunkedDecoder, AbstractDecoder() { // A mutable reference to the discriminator that have to be skipped when in optimistic phase // of polymorphic serialization, see `decodeSerializableValue` @@ -93,7 +94,6 @@ internal open class StreamingJsonDecoder( } discriminatorHolder = DiscriminatorHolder(discriminator) - @Suppress("UNCHECKED_CAST") return actualSerializer.deserialize(this) as T @@ -149,7 +149,7 @@ internal open class StreamingJsonDecoder( } override fun decodeNotNullMark(): Boolean { - return !(elementMarker?.isUnmarkedNull ?: false) && lexer.tryConsumeNotNull() + return !(elementMarker?.isUnmarkedNull ?: false) && !lexer.tryConsumeNull() } override fun decodeNull(): Nothing? { @@ -225,7 +225,7 @@ internal open class StreamingJsonDecoder( private fun coerceInputValue(descriptor: SerialDescriptor, index: Int): Boolean = json.tryCoerceValue( descriptor.getElementDescriptor(index), - { !lexer.tryConsumeNotNull() }, + { lexer.tryConsumeNull(it) }, { lexer.peekString(configuration.isLenient) }, { lexer.consumeString() /* skip unknown enum string*/ } ) @@ -362,6 +362,10 @@ internal open class StreamingJsonDecoder( } } + override fun decodeStringChunked(consumeChunk: (chunk: String) -> Unit) { + lexer.consumeStringChunked(configuration.isLenient, consumeChunk) + } + override fun decodeInline(descriptor: SerialDescriptor): Decoder = if (descriptor.isUnsignedNumber) JsonDecoderForUnsignedTypes(lexer, json) else super.decodeInline(descriptor) diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/lexer/AbstractJsonLexer.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/lexer/AbstractJsonLexer.kt index 893045edf..3c6712573 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/lexer/AbstractJsonLexer.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/lexer/AbstractJsonLexer.kt @@ -251,25 +251,28 @@ internal abstract class AbstractJsonLexer { /** * Tries to consume `null` token from input. - * Returns `true` if the next 4 chars in input are not `null`, - * `false` otherwise and consumes it. + * Returns `false` if the next 4 chars in input are not `null`, + * `true` otherwise and consumes it if [doConsume] is `true`. */ - fun tryConsumeNotNull(): Boolean { + fun tryConsumeNull(doConsume: Boolean = true): Boolean { var current = skipWhitespaces() current = prefetchOrEof(current) // Cannot consume null due to EOF, maybe something else val len = source.length - current - if (len < 4 || current == -1) return true + if (len < 4 || current == -1) return false for (i in 0..3) { - if (NULL[i] != source[current + i]) return true + if (NULL[i] != source[current + i]) return false } /* * If we're in lenient mode, this might be the string with 'null' prefix, * distinguish it from 'null' */ - if (len > 4 && charToTokenClass(source[current + 4]) == TC_OTHER) return true - currentPosition = current + 4 - return false + if (len > 4 && charToTokenClass(source[current + 4]) == TC_OTHER) return false + + if (doConsume) { + currentPosition = current + 4 + } + return true } open fun skipWhitespaces(): Int { @@ -314,6 +317,66 @@ internal abstract class AbstractJsonLexer { */ abstract fun consumeKeyString(): String + private fun insideString(isLenient: Boolean, char: Char): Boolean = if (isLenient) { + charToTokenClass(char) == TC_OTHER + } else { + char != STRING + } + + open fun consumeStringChunked( + isLenient: Boolean, + consumeChunk: (stringChunk: String) -> Unit + ) { // open to allow simpler implementations (i.e. StringJsonLexer) + val nextToken = peekNextToken() + if (isLenient && nextToken != TC_OTHER) return // noting to consume + + if (!isLenient) { + consumeNextToken(STRING) + } + var currentPosition = this.currentPosition + var lastPosition = currentPosition + var char = source[currentPosition] // Avoid two range checks visible in the profiler + var usedAppend = false + while (insideString(isLenient, char)) { + if (!isLenient && char == STRING_ESC) { // handle escaping only in non-lenient mode + usedAppend = true + currentPosition = prefetchOrEof(appendEscape(lastPosition, currentPosition)) + lastPosition = currentPosition + } else { + currentPosition++ + } + if (currentPosition >= source.length) { + // end of chunk + writeRange(lastPosition, currentPosition, usedAppend, consumeChunk) + usedAppend = false + currentPosition = prefetchOrEof(currentPosition) + if (currentPosition == -1) + fail("EOF", currentPosition) + lastPosition = currentPosition + } + char = source[currentPosition] + } + writeRange(lastPosition, currentPosition, usedAppend, consumeChunk) + this.currentPosition = currentPosition + if (!isLenient) { + consumeNextToken(STRING) + } + } + + private fun writeRange( + fromIndex: Int, + toIndex: Int, + currentChunkHasEscape: Boolean, + consumeChunk: (stringChunk: String) -> Unit + ) { + if (currentChunkHasEscape) { + consumeChunk(decodedString(fromIndex, toIndex)) + } else { + consumeChunk(substring(fromIndex, toIndex)) + } + } + + fun consumeString(): String { if (peekedString != null) { return takePeeked() diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/lexer/StringJsonLexer.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/lexer/StringJsonLexer.kt index afc48c98e..a22f51724 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/lexer/StringJsonLexer.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/json/internal/lexer/StringJsonLexer.kt @@ -103,6 +103,14 @@ internal class StringJsonLexer(override val source: String) : AbstractJsonLexer( return source.substring(current, closingQuote) } + override fun consumeStringChunked( + isLenient: Boolean, + consumeChunk: (stringChunk: String) -> Unit + ) { + (if (isLenient) consumeStringLenient() else consumeString()).chunked(BATCH_SIZE) + .forEach(consumeChunk) + } + override fun consumeLeadingMatchingValue(keyToMatch: String, isLenient: Boolean): String? { val positionSnapshot = currentPosition try { diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/msgpack/MsgPackTreeReader.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/msgpack/MsgPackTreeReader.kt index aee4c76d6..d37c7a9fa 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/msgpack/MsgPackTreeReader.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/msgpack/MsgPackTreeReader.kt @@ -32,7 +32,7 @@ internal class MsgPackTreeReader( .joinToNumber() type == MsgPackType.Array.ARRAY32 -> { - if (basicMsgPackDecoder.configuration.preventOverflows) { + if (basicMsgPackDecoder.getConfiguration().preventOverflows) { val number = basicMsgPackDecoder.dataBuffer.takeNext(4).joinToNumber() if (number !in Int.MIN_VALUE..Int.MAX_VALUE) { throw MsgPackSerializationException.overflowError(basicMsgPackDecoder.dataBuffer) @@ -64,7 +64,7 @@ internal class MsgPackTreeReader( .joinToNumber() type == MsgPackType.Map.MAP32 -> { - if (basicMsgPackDecoder.configuration.preventOverflows) { + if (basicMsgPackDecoder.getConfiguration().preventOverflows) { val number = basicMsgPackDecoder.dataBuffer.takeNext(4).joinToNumber() if (number !in Int.MIN_VALUE..Int.MAX_VALUE) { throw MsgPackSerializationException.overflowError(basicMsgPackDecoder.dataBuffer) diff --git a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/msgpack/internal/MsgPackDecoder.kt b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/msgpack/internal/MsgPackDecoder.kt index bcea224bd..f6b318b90 100644 --- a/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/msgpack/internal/MsgPackDecoder.kt +++ b/app_filegallery/src/main/kotlin/dev/ragnarok/filegallery/util/serializeble/msgpack/internal/MsgPackDecoder.kt @@ -22,26 +22,27 @@ interface MsgPackTypeDecoder { } internal class BasicMsgPackDecoder( - val configuration: MsgPackConfiguration, + private val configuration: MsgPackConfiguration, override val serializersModule: SerializersModule, val dataBuffer: MsgPackDataInputBuffer, private val msgUnpacker: MsgUnpacker = BasicMsgUnpacker(dataBuffer), val inlineDecoders: Map Decoder> = mapOf() ) : AbstractDecoder(), MsgPackTypeDecoder { fun decodeMsgPackElement(): JsonElement = MsgPackTreeReader(this).read() + fun getConfiguration(): MsgPackConfiguration { + return configuration + } - val depthStack: ArrayDeque = ArrayDeque() - - override fun decodeElementIndex(descriptor: SerialDescriptor): Int { + internal fun decodeElementIndexInternal(descriptor: SerialDescriptor): Int { if (descriptor.kind in arrayOf(StructureKind.CLASS, StructureKind.OBJECT)) { val next = dataBuffer.peekSafely() if (next != null && MsgPackType.String.isString(next)) { val fieldName = kotlin.runCatching { decodeString() }.getOrNull() ?: return CompositeDecoder.UNKNOWN_NAME val index = descriptor.getElementIndex(fieldName) - return if (index == CompositeDecoder.UNKNOWN_NAME && configuration.ignoreUnknownKeys && depthStack.isEmpty()) { + return if (index == CompositeDecoder.UNKNOWN_NAME && configuration.ignoreUnknownKeys) { MsgPackNullableDynamicSerializer.deserialize(this) - decodeElementIndex(descriptor) + index } else { index } @@ -52,6 +53,14 @@ internal class BasicMsgPackDecoder( return 0 } + override fun decodeElementIndex(descriptor: SerialDescriptor): Int { + val result = decodeElementIndexInternal(descriptor) + if (result == CompositeDecoder.UNKNOWN_NAME && configuration.ignoreUnknownKeys) { + return decodeElementIndex(descriptor) + } + return result + } + override fun decodeSequentially(): Boolean = true override fun decodeNotNullMark(): Boolean { @@ -222,19 +231,12 @@ internal class BasicMsgPackDecoder( return ExtensionTypeDecoder(this) } - depthStack.addFirst(Unit) - // Handle extension types as arrays val size = decodeCollectionSize(descriptor) - return ClassMsgPackDecoder(this, size) + return ClassMsgPackDecoder(this, configuration, size) } return this } - override fun endStructure(descriptor: SerialDescriptor) { - super.endStructure(descriptor) - depthStack.removeFirstOrNull() - } - override fun peekNextType(): Byte { return dataBuffer.peek() } @@ -249,42 +251,19 @@ internal class MsgPackDecoder( internal class ClassMsgPackDecoder( private val basicMsgPackDecoder: BasicMsgPackDecoder, + private val configuration: MsgPackConfiguration, private val size: Int ) : Decoder by basicMsgPackDecoder, CompositeDecoder by basicMsgPackDecoder, MsgPackTypeDecoder by basicMsgPackDecoder { override val serializersModule: SerializersModule = basicMsgPackDecoder.serializersModule - private fun decodeElemIndex(descriptor: SerialDescriptor, size: Int): Int { - if (descriptor.kind in arrayOf(StructureKind.CLASS, StructureKind.OBJECT)) { - val next = basicMsgPackDecoder.dataBuffer.peekSafely() - if (next != null && MsgPackType.String.isString(next)) { - val fieldName = kotlin.runCatching { decodeString() }.getOrNull() - ?: return CompositeDecoder.UNKNOWN_NAME - val index = descriptor.getElementIndex(fieldName) - return if (index == CompositeDecoder.UNKNOWN_NAME && basicMsgPackDecoder.configuration.ignoreUnknownKeys && basicMsgPackDecoder.depthStack.isEmpty()) { - MsgPackNullableDynamicSerializer.deserialize(this) - decodedElements++ - if (decodedElements >= size) CompositeDecoder.DECODE_DONE else decodeElemIndex( - descriptor, - size - ) - } else { - index - } - } else { - return CompositeDecoder.DECODE_DONE - } - } - return 0 - } private var decodedElements = 0 override fun decodeElementIndex(descriptor: SerialDescriptor): Int { if (decodedElements >= size) return CompositeDecoder.DECODE_DONE - val result = decodeElemIndex(descriptor, size) + val result = basicMsgPackDecoder.decodeElementIndexInternal(descriptor) if (result != CompositeDecoder.DECODE_DONE) decodedElements++ - return if (result == CompositeDecoder.UNKNOWN_NAME) { - MsgPackNullableDynamicSerializer.deserialize(this) + return if (result == CompositeDecoder.UNKNOWN_NAME && configuration.ignoreUnknownKeys) { decodeElementIndex(descriptor) } else { result diff --git a/app_filegallery/src/main/res/values-be/strings.xml b/app_filegallery/src/main/res/values-be/strings.xml index 5450477b1..d45251cf8 100644 --- a/app_filegallery/src/main/res/values-be/strings.xml +++ b/app_filegallery/src/main/res/values-be/strings.xml @@ -32,14 +32,6 @@ Material 1 - - Па змаўчанні - Маленькі - Сярэдні - Вялікі - Вялізны - - 1 хвіл. 2 хвіл. diff --git a/app_filegallery/src/main/res/values-ru/strings.xml b/app_filegallery/src/main/res/values-ru/strings.xml index fa0056737..44f5f054d 100644 --- a/app_filegallery/src/main/res/values-ru/strings.xml +++ b/app_filegallery/src/main/res/values-ru/strings.xml @@ -32,14 +32,6 @@ Material 1 - - По умолчанию - Маленький - Средний - Большой - Огромный - - 1 мин. 2 мин. diff --git a/app_filegallery/src/main/res/values/strings.xml b/app_filegallery/src/main/res/values/strings.xml index b4140e1d8..1e9815e81 100644 --- a/app_filegallery/src/main/res/values/strings.xml +++ b/app_filegallery/src/main/res/values/strings.xml @@ -52,22 +52,6 @@ 2 - - Default - Small - Average - Large - Huge - - - - 0 - -1 - 1 - 2 - 3 - - 1 min. 2 min. diff --git a/build.gradle b/build.gradle index 86a9e0f56..57a096143 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { ext.is_developer_build = true ext.appCompileSDK = 33 - ext.appBuildTools = "33.0.1" + ext.appBuildTools = "33.0.2" ext.appNdk = "25.2.9519653" ext.appMinSDK = is_developer_build ? 29 : 21 ext.appTargetSDK = 31 @@ -13,24 +13,25 @@ buildscript { ext.appFileGalleryVersionName = "1.999" //androidx libraries - ext.activityVersion = "1.7.0-beta01" - ext.annotationVersion = "1.6.0-rc01" + ext.activityVersion = "1.7.0-beta02" + ext.annotationVersion = "1.6.0" ext.appcompatVersion = "1.6.1" ext.biometricVersion = "1.2.0-alpha05" ext.browserVersion = "1.5.0" ext.cameraVersion = "1.2.1" ext.cardviewVersion = "1.0.0" ext.collectionVersion = "1.3.0-alpha02" - ext.constraintlayoutVersion = "2.1.4" + ext.concurentVersion = "1.2.0-alpha01" + ext.constraintlayoutVersion = "2.2.0-alpha07" ext.coordinatorlayoutVersion = "1.2.0" - ext.coreVersion = "1.9.0" + ext.coreVersion = "1.10.0-beta01" ext.customviewVersion = "1.2.0-alpha02" ext.customviewPoolingcontainerVersion = "1.0.0" ext.dynamicanimationVersion = "1.1.0-alpha03" ext.drawerlayoutVersion = "1.2.0-beta01" ext.exifinterfaceVersion = "1.3.6" - ext.fragmentVersion = "1.6.0-alpha05" - ext.lifecycleVersion = "2.6.0-beta01" + ext.fragmentVersion = "1.6.0-alpha06" + ext.lifecycleVersion = "2.6.0-rc01" ext.loaderVersion = "1.1.0" ext.mediaVersion = "1.7.0-alpha01" ext.recyclerviewVersion = "1.3.0-rc01" @@ -50,21 +51,21 @@ buildscript { ext.firebaseCommonVersion = "20.3.0" ext.firebaseInstallationsInteropVersion = "17.1.0" ext.firebaseComponentsVersion = "17.1.0" - ext.firebaseAnnotationsVersion = "16.1.0" + ext.firebaseAnnotationsVersion = "16.2.0" ext.playServicesTasksVersion = "18.0.2" ext.autoValueVersion = "1.10.1" //common libraries ext.kotlin_version = "1.8.10" ext.kotlin_coroutines = "1.6.4" - ext.kotlin_serializer = "1.5.0-RC" + ext.kotlin_serializer = "1.5.0" ext.okhttpLibraryVersion = "5.0.0-alpha.11" ext.okioVersion = "3.3.0" ext.rxJavaVersion = "3.1.6" ext.guavaVersion = "31.1-android" - ext.exoLibraryVersion = "2.18.2" + ext.exoLibraryVersion = "2.18.3" ext.errorproneVersion = "2.15.0" - ext.desugarLibraryVersion = "2.0.0" + ext.desugarLibraryVersion = "2.0.2" //APP_PROPS ext.targetAbi = is_developer_build ? ["arm64-v8a", "x86_64"] : ["arm64-v8a", "armeabi-v7a", "x86_64"] @@ -81,13 +82,14 @@ buildscript { ext.vk_app_finger_print = "48761EEF50EE53AFC4CC9C5F10E6BDE7F8F5B82F" ext.kate_app_package = "com.perm.kate_new_6" ext.kate_app_finger_print = "966882BA564C2619D55D0A9AFD4327A38C327456" + //keytool -printcert -jarfile *.apk repositories { google() mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:8.0.0-beta02" + classpath "com.android.tools.build:gradle:8.0.0-beta03" classpath "com.google.gms:google-services:4.3.15" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" diff --git a/camera2/build.gradle b/camera2/build.gradle index 02b6bd82b..4110b009f 100644 --- a/camera2/build.gradle +++ b/camera2/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-android-extensions-runtime:$kotlin_version") compileOnly("org.jetbrains.kotlin:kotlin-annotations-jvm:$kotlin_version") compileOnly("org.checkerframework:checker-compat-qual:2.5.5") - compileOnly("org.checkerframework:checker-qual-android:3.27.0") + compileOnly("org.checkerframework:checker-qual-android:3.31.0") compileOnly("com.google.auto.value:auto-value-annotations:$autoValueVersion") implementation("androidx.annotation:annotation:$annotationVersion") implementation("androidx.appcompat:appcompat:$appcompatVersion") @@ -40,6 +40,6 @@ dependencies { implementation("com.google.errorprone:error_prone_annotations:${errorproneVersion}") implementation("androidx.exifinterface:exifinterface:$exifinterfaceVersion") implementation("com.google.guava:guava:$guavaVersion") - implementation("androidx.concurrent:concurrent-futures:1.1.0") + implementation("androidx.concurrent:concurrent-futures:$concurentVersion") annotationProcessor("com.google.auto.value:auto-value:$autoValueVersion") } diff --git a/firebase-installations/build.gradle b/firebase-installations/build.gradle index d56d093e7..0eb99a6a5 100644 --- a/firebase-installations/build.gradle +++ b/firebase-installations/build.gradle @@ -41,7 +41,7 @@ android { defaultConfig { minSdk = appMinSDK targetSdk = appTargetSDK - buildConfigField("String", "VERSION_NAME", asStringVar("17.0.2")) + buildConfigField("String", "VERSION_NAME_INSTALLATION", asStringVar("17.0.2")) } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallationsRegistrar.java b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallationsRegistrar.java index 1f0b7b4fe..b8e157d10 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallationsRegistrar.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallationsRegistrar.java @@ -59,6 +59,6 @@ public List> getComponents() { c.get(Qualified.qualified(Blocking.class, Executor.class))))) .build(), HeartBeatConsumerComponent.create(), - LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME)); + LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME_INSTALLATION)); } } diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClient.java b/firebase-installations/src/main/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClient.java index 819ba498c..d5c9f7895 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClient.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClient.java @@ -16,7 +16,7 @@ import static android.content.ContentValues.TAG; import static com.google.android.gms.common.internal.Preconditions.checkArgument; -import static com.google.firebase.installations.BuildConfig.VERSION_NAME; +import static com.google.firebase.installations.BuildConfig.VERSION_NAME_INSTALLATION; import android.net.TrafficStats; import android.text.TextUtils; @@ -155,7 +155,7 @@ private static JSONObject buildCreateFirebaseInstallationRequestBody( firebaseInstallationData.put("fid", fid); firebaseInstallationData.put("appId", appId); firebaseInstallationData.put("authVersion", FIREBASE_INSTALLATION_AUTH_VERSION); - firebaseInstallationData.put("sdkVersion", SDK_VERSION_PREFIX + VERSION_NAME); + firebaseInstallationData.put("sdkVersion", SDK_VERSION_PREFIX + VERSION_NAME_INSTALLATION); return firebaseInstallationData; } catch (JSONException e) { throw new IllegalStateException(e); @@ -173,7 +173,7 @@ private static JSONObject buildCreateFirebaseInstallationRequestBody( private static JSONObject buildGenerateAuthTokenRequestBody() { try { JSONObject sdkVersionData = new JSONObject(); - sdkVersionData.put("sdkVersion", SDK_VERSION_PREFIX + VERSION_NAME); + sdkVersionData.put("sdkVersion", SDK_VERSION_PREFIX + VERSION_NAME_INSTALLATION); JSONObject firebaseInstallationData = new JSONObject(); firebaseInstallationData.put("installation", sdkVersionData); diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5e1f8d81b..5f6d01f8a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Aug 17 12:17:04 MSK 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-rc-3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/libfenrir/ffmpeg.sh b/libfenrir/ffmpeg.sh index 73cfa2712..933d1214a 100644 --- a/libfenrir/ffmpeg.sh +++ b/libfenrir/ffmpeg.sh @@ -1,9 +1,9 @@ #!/bin/bash SCRIPT_DIR=${PWD} cd ~/ -git clone git://source.ffmpeg.org/ffmpeg +git clone https://git.videolan.org/git/ffmpeg.git cd ffmpeg -git checkout release/5.1 +git checkout release/6.0 rm -r -f ".git" ENABLED_DECODERS=(gif mpeg4 h264 hevc mp3 aac ac3 eac3 flac vorbis alac) diff --git a/libfenrir/src/main/java/com/github/luben/zstd/BaseZstdBufferDecompressingStreamNoFinalizer.java b/libfenrir/src/main/java/com/github/luben/zstd/BaseZstdBufferDecompressingStreamNoFinalizer.java index 5e0a1e16d..b45081579 100644 --- a/libfenrir/src/main/java/com/github/luben/zstd/BaseZstdBufferDecompressingStreamNoFinalizer.java +++ b/libfenrir/src/main/java/com/github/luben/zstd/BaseZstdBufferDecompressingStreamNoFinalizer.java @@ -26,7 +26,7 @@ public abstract class BaseZstdBufferDecompressingStreamNoFinalizer implements Cl protected ByteBuffer refill(ByteBuffer toRefill) { return toRefill; } - + public boolean hasRemaining() { return !streamEnd && (source.hasRemaining() || !finishedFrame); } diff --git a/libfenrir/src/main/java/com/github/luben/zstd/EndDirective.java b/libfenrir/src/main/java/com/github/luben/zstd/EndDirective.java index 4fbb1c9b6..84f6d6eb6 100644 --- a/libfenrir/src/main/java/com/github/luben/zstd/EndDirective.java +++ b/libfenrir/src/main/java/com/github/luben/zstd/EndDirective.java @@ -10,7 +10,7 @@ public enum EndDirective { END(2); private final int value; - EndDirective(int value) { + private EndDirective(int value) { this.value = value; } diff --git a/libfenrir/src/main/java/com/github/luben/zstd/ZstdCompressCtx.java b/libfenrir/src/main/java/com/github/luben/zstd/ZstdCompressCtx.java index 7efec84a8..4477b4893 100644 --- a/libfenrir/src/main/java/com/github/luben/zstd/ZstdCompressCtx.java +++ b/libfenrir/src/main/java/com/github/luben/zstd/ZstdCompressCtx.java @@ -61,7 +61,7 @@ public ZstdCompressCtx setMagicless(boolean magiclessFlag) { releaseSharedLock(); return this; } - + /** * Enable or disable compression checksums * @param checksumFlag A 32-bits checksum of content is written at end of frame, default: false @@ -199,7 +199,7 @@ public ZstdFrameProgression getFrameProgression() { return getFrameProgression0(); } private native ZstdFrameProgression getFrameProgression0(); - + /** * Clear all state and parameters from the compression context. This leaves the object in a * state identical to a newly created compression context. diff --git a/libfenrir/src/main/java/com/github/luben/zstd/ZstdDecompressCtx.java b/libfenrir/src/main/java/com/github/luben/zstd/ZstdDecompressCtx.java index 47e5bae43..5f1ac5894 100644 --- a/libfenrir/src/main/java/com/github/luben/zstd/ZstdDecompressCtx.java +++ b/libfenrir/src/main/java/com/github/luben/zstd/ZstdDecompressCtx.java @@ -44,7 +44,7 @@ public ZstdDecompressCtx setMagicless(boolean magiclessFlag) { releaseSharedLock(); return this; } - + /** * Load decompression dictionary * diff --git a/libfenrir/src/main/java/com/github/luben/zstd/ZstdFrameProgression.java b/libfenrir/src/main/java/com/github/luben/zstd/ZstdFrameProgression.java index b8011858a..cb1577452 100644 --- a/libfenrir/src/main/java/com/github/luben/zstd/ZstdFrameProgression.java +++ b/libfenrir/src/main/java/com/github/luben/zstd/ZstdFrameProgression.java @@ -67,5 +67,5 @@ public int getCurrentJobID() { public int getNbActiveWorkers() { return nbActiveWorkers; } - + } diff --git a/libfenrir/src/main/jni/animation/animation_jni.cpp b/libfenrir/src/main/jni/animation/animation_jni.cpp index 093aeb3df..d92a9515a 100644 --- a/libfenrir/src/main/jni/animation/animation_jni.cpp +++ b/libfenrir/src/main/jni/animation/animation_jni.cpp @@ -33,7 +33,8 @@ static inline void print_ffmpeg_error(int error) { } */ -struct VideoInfo { +class VideoInfo { +public: ~VideoInfo() { if (video_dec_ctx) { avcodec_close(video_dec_ctx); @@ -651,4 +652,4 @@ Java_dev_ragnarok_fenrir_module_animation_AnimatedFileDrawable_getVideoFrame(JNI } } return 0; -} +} \ No newline at end of file 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 b773f886e..64d0b59f7 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 @@ -232,6 +232,27 @@ void TransposeWx1_16_C(const uint16_t* src, uint16_t* dst, int dst_stride, int width); + +// Transpose 32 bit values (ARGB) +void Transpose4x4_32_NEON(const uint8_t* src, + int src_stride, + uint8_t* dst, + int dst_stride, + int width); + +void Transpose4x4_32_C(const uint8_t* src, + int src_stride, + uint8_t* dst, + int dst_stride, + int width); + +// Transpose 32 bit values (ARGB) +void Transpose8x8_32_NEON(const uint8_t* src, + int src_stride, + uint8_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 8d998727f..ff6ffe47c 100644 --- a/libfenrir/src/main/jni/animation/libyuv/include/libyuv/row.h +++ b/libfenrir/src/main/jni/animation/libyuv/include/libyuv/row.h @@ -403,8 +403,9 @@ extern "C" { // TODO(fbarchard): Port to GCC and Visual C // TODO(fbarchard): re-enable HAS_ARGBTORGB24ROW_AVX512VBMI. Issue libyuv:789 #if !defined(LIBYUV_DISABLE_X86) && \ - (defined(__x86_64__) || defined(__i386__)) && (defined(CLANG_HAS_AVX512)) + (defined(__x86_64__) || defined(__i386__)) && defined(CLANG_HAS_AVX512) #define HAS_ARGBTORGB24ROW_AVX512VBMI +#define HAS_MERGEUVROW_AVX512BW #endif // The following are available for AVX512 clang x64 platforms: @@ -2184,6 +2185,10 @@ void MergeUVRow_AVX2(const uint8_t* src_u, const uint8_t* src_v, uint8_t* dst_uv, int width); +void MergeUVRow_AVX512BW(const uint8_t* src_u, + const uint8_t* src_v, + uint8_t* dst_uv, + int width); void MergeUVRow_NEON(const uint8_t* src_u, const uint8_t* src_v, uint8_t* dst_uv, @@ -2204,6 +2209,10 @@ void MergeUVRow_Any_AVX2(const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* dst_ptr, int width); +void MergeUVRow_Any_AVX512BW(const uint8_t* y_buf, + const uint8_t* uv_buf, + uint8_t* dst_ptr, + int width); void MergeUVRow_Any_NEON(const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* dst_ptr, 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 adc49c4e4..42f816626 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 1857 +#define LIBYUV_VERSION 1861 #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 15c70a659..37b7091b1 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/convert.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/convert.cc @@ -919,11 +919,19 @@ int I422ToNV21(const uint8_t* src_y, #if defined(HAS_MERGEUVROW_AVX2) if (TestCpuFlag(kCpuHasAVX2)) { MergeUVRow = MergeUVRow_Any_AVX2; - if (IS_ALIGNED(halfwidth, 32)) { + if (IS_ALIGNED(halfwidth, 16)) { MergeUVRow = MergeUVRow_AVX2; } } #endif +#if defined(HAS_MERGEUVROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + MergeUVRow = MergeUVRow_Any_AVX512BW; + if (IS_ALIGNED(halfwidth, 32)) { + MergeUVRow = MergeUVRow_AVX512BW; + } + } +#endif #if defined(HAS_MERGEUVROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { MergeUVRow = MergeUVRow_Any_NEON; diff --git a/libfenrir/src/main/jni/animation/libyuv/source/convert_from_argb.cc b/libfenrir/src/main/jni/animation/libyuv/source/convert_from_argb.cc index d548aec28..55516cbd8 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/convert_from_argb.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/convert_from_argb.cc @@ -384,11 +384,19 @@ int ARGBToNV12(const uint8_t* src_argb, #if defined(HAS_MERGEUVROW_AVX2) if (TestCpuFlag(kCpuHasAVX2)) { MergeUVRow_ = MergeUVRow_Any_AVX2; - if (IS_ALIGNED(halfwidth, 32)) { + if (IS_ALIGNED(halfwidth, 16)) { MergeUVRow_ = MergeUVRow_AVX2; } } #endif +#if defined(HAS_MERGEUVROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + MergeUVRow_ = MergeUVRow_Any_AVX512BW; + if (IS_ALIGNED(halfwidth, 32)) { + MergeUVRow_ = MergeUVRow_AVX512BW; + } + } +#endif #if defined(HAS_MERGEUVROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { MergeUVRow_ = MergeUVRow_Any_NEON; @@ -554,11 +562,19 @@ int ARGBToNV21(const uint8_t* src_argb, #if defined(HAS_MERGEUVROW_AVX2) if (TestCpuFlag(kCpuHasAVX2)) { MergeUVRow_ = MergeUVRow_Any_AVX2; - if (IS_ALIGNED(halfwidth, 32)) { + if (IS_ALIGNED(halfwidth, 16)) { MergeUVRow_ = MergeUVRow_AVX2; } } #endif +#if defined(HAS_MERGEUVROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + MergeUVRow_ = MergeUVRow_Any_AVX512BW; + if (IS_ALIGNED(halfwidth, 64)) { + MergeUVRow_ = MergeUVRow_AVX512BW; + } + } +#endif #if defined(HAS_MERGEUVROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { MergeUVRow_ = MergeUVRow_Any_NEON; @@ -721,11 +737,19 @@ int ABGRToNV12(const uint8_t* src_abgr, #if defined(HAS_MERGEUVROW_AVX2) if (TestCpuFlag(kCpuHasAVX2)) { MergeUVRow_ = MergeUVRow_Any_AVX2; - if (IS_ALIGNED(halfwidth, 32)) { + if (IS_ALIGNED(halfwidth, 16)) { MergeUVRow_ = MergeUVRow_AVX2; } } #endif +#if defined(HAS_MERGEUVROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + MergeUVRow_ = MergeUVRow_Any_AVX512BW; + if (IS_ALIGNED(halfwidth, 64)) { + MergeUVRow_ = MergeUVRow_AVX512BW; + } + } +#endif #if defined(HAS_MERGEUVROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { MergeUVRow_ = MergeUVRow_Any_NEON; @@ -889,11 +913,19 @@ int ABGRToNV21(const uint8_t* src_abgr, #if defined(HAS_MERGEUVROW_AVX2) if (TestCpuFlag(kCpuHasAVX2)) { MergeUVRow_ = MergeUVRow_Any_AVX2; - if (IS_ALIGNED(halfwidth, 32)) { + if (IS_ALIGNED(halfwidth, 16)) { MergeUVRow_ = MergeUVRow_AVX2; } } #endif +#if defined(HAS_MERGEUVROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + MergeUVRow_ = MergeUVRow_Any_AVX512BW; + if (IS_ALIGNED(halfwidth, 64)) { + MergeUVRow_ = MergeUVRow_AVX512BW; + } + } +#endif #if defined(HAS_MERGEUVROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { MergeUVRow_ = MergeUVRow_Any_NEON; @@ -2916,11 +2948,19 @@ int RAWToJNV21(const uint8_t* src_raw, #if defined(HAS_MERGEUVROW_AVX2) if (TestCpuFlag(kCpuHasAVX2)) { MergeUVRow_ = MergeUVRow_Any_AVX2; - if (IS_ALIGNED(halfwidth, 32)) { + if (IS_ALIGNED(halfwidth, 16)) { MergeUVRow_ = MergeUVRow_AVX2; } } #endif +#if defined(HAS_MERGEUVROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + MergeUVRow_ = MergeUVRow_Any_AVX512BW; + if (IS_ALIGNED(halfwidth, 64)) { + MergeUVRow_ = MergeUVRow_AVX512BW; + } + } +#endif #if defined(HAS_MERGEUVROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { MergeUVRow_ = MergeUVRow_Any_NEON; 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 e08a44f6f..e3452f58e 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/planar_functions.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/planar_functions.cc @@ -162,7 +162,7 @@ void Convert8To16Plane(const uint8_t* src_y, int src_stride_y, uint16_t* dst_y, int dst_stride_y, - int scale, // 16384 for 10 bits + int scale, // 1024 for 10 bits int width, int height) { int y; @@ -594,11 +594,19 @@ void MergeUVPlane(const uint8_t* src_u, #if defined(HAS_MERGEUVROW_AVX2) if (TestCpuFlag(kCpuHasAVX2)) { MergeUVRow = MergeUVRow_Any_AVX2; - if (IS_ALIGNED(width, 32)) { + if (IS_ALIGNED(width, 16)) { MergeUVRow = MergeUVRow_AVX2; } } #endif +#if defined(HAS_MERGEUVROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + MergeUVRow = MergeUVRow_Any_AVX512BW; + if (IS_ALIGNED(width, 32)) { + MergeUVRow = MergeUVRow_AVX512BW; + } + } +#endif #if defined(HAS_MERGEUVROW_NEON) if (TestCpuFlag(kCpuHasNEON)) { MergeUVRow = MergeUVRow_Any_NEON; @@ -728,7 +736,7 @@ void MergeUVPlane_16(const uint16_t* src_u, #if defined(HAS_MERGEUVROW_16_AVX2) if (TestCpuFlag(kCpuHasAVX2)) { MergeUVRow_16 = MergeUVRow_16_Any_AVX2; - if (IS_ALIGNED(width, 16)) { + if (IS_ALIGNED(width, 8)) { MergeUVRow_16 = MergeUVRow_16_AVX2; } } 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 2617c01b2..4b496d1b3 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/rotate_common.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/rotate_common.cc @@ -166,6 +166,63 @@ void TransposeWxH_16_C(const uint16_t* src, } } +// Transpose 32 bit values (ARGB) +void Transpose4x4_32_C(const uint8_t* src, + int src_stride, + uint8_t* dst, + int dst_stride, + int width) { + const uint8_t* src1 = src + src_stride; + const uint8_t* src2 = src1 + src_stride; + const uint8_t* src3 = src2 + src_stride; + uint8_t* dst1 = dst + dst_stride; + uint8_t* dst2 = dst1 + dst_stride; + uint8_t* dst3 = dst2 + dst_stride; + int i; + for (i = 0; i < width; i += 4) { + uint32_t p00 = ((uint32_t*)(src))[0]; + uint32_t p10 = ((uint32_t*)(src))[1]; + uint32_t p20 = ((uint32_t*)(src))[2]; + uint32_t p30 = ((uint32_t*)(src))[3]; + uint32_t p01 = ((uint32_t*)(src1))[0]; + uint32_t p11 = ((uint32_t*)(src1))[1]; + uint32_t p21 = ((uint32_t*)(src1))[2]; + uint32_t p31 = ((uint32_t*)(src1))[3]; + uint32_t p02 = ((uint32_t*)(src2))[0]; + uint32_t p12 = ((uint32_t*)(src2))[1]; + uint32_t p22 = ((uint32_t*)(src2))[2]; + uint32_t p32 = ((uint32_t*)(src2))[3]; + uint32_t p03 = ((uint32_t*)(src3))[0]; + uint32_t p13 = ((uint32_t*)(src3))[1]; + uint32_t p23 = ((uint32_t*)(src3))[2]; + uint32_t p33 = ((uint32_t*)(src3))[3]; + ((uint32_t*)(dst))[0] = p00; + ((uint32_t*)(dst))[1] = p01; + ((uint32_t*)(dst))[2] = p02; + ((uint32_t*)(dst))[3] = p03; + ((uint32_t*)(dst1))[0] = p10; + ((uint32_t*)(dst1))[1] = p11; + ((uint32_t*)(dst1))[2] = p12; + ((uint32_t*)(dst1))[3] = p13; + ((uint32_t*)(dst2))[0] = p20; + ((uint32_t*)(dst2))[1] = p21; + ((uint32_t*)(dst2))[2] = p22; + ((uint32_t*)(dst2))[3] = p23; + ((uint32_t*)(dst3))[0] = p30; + ((uint32_t*)(dst3))[1] = p31; + ((uint32_t*)(dst3))[2] = p32; + ((uint32_t*)(dst3))[3] = p33; + src += src_stride * 4; // advance 4 rows + src1 += src_stride * 4; + src2 += src_stride * 4; + src3 += src_stride * 4; + dst += 4 * 4; // advance 4 columns + dst1 += 4 * 4; + dst2 += 4 * 4; + dst3 += 4 * 4; + } +} + #ifdef __cplusplus } // extern "C" } // namespace libyuv diff --git a/libfenrir/src/main/jni/animation/libyuv/source/rotate_neon64.cc b/libfenrir/src/main/jni/animation/libyuv/source/rotate_neon64.cc index ea1cf82c2..95047fa7a 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/rotate_neon64.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/rotate_neon64.cc @@ -435,6 +435,45 @@ void TransposeUVWx8_NEON(const uint8_t* src, : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v30", "v31"); } + +// Transpose 32 bit values (ARGB) +void Transpose4x4_32_NEON(const uint8_t* src, + int src_stride, + uint8_t* dst, + int dst_stride, + int width) { + const uint8_t* src1 = src + src_stride; + const uint8_t* src2 = src1 + src_stride; + const uint8_t* src3 = src2 + src_stride; + uint8_t* dst1 = dst + dst_stride; + uint8_t* dst2 = dst1 + dst_stride; + uint8_t* dst3 = dst2 + dst_stride; + asm volatile( + // Main loop transpose 4x4. Read a column, write a row. + "1: \n" + "ld4 {v0.s, v1.s, v2.s, v3.s}[0], [%0], %9 \n" + "ld4 {v0.s, v1.s, v2.s, v3.s}[1], [%1], %9 \n" + "ld4 {v0.s, v1.s, v2.s, v3.s}[2], [%2], %9 \n" + "ld4 {v0.s, v1.s, v2.s, v3.s}[3], [%3], %9 \n" + "subs %w8, %w8, #4 \n" // w -= 4 + "st1 {v0.4s}, [%4], 16 \n" + "st1 {v1.4s}, [%5], 16 \n" + "st1 {v2.4s}, [%6], 16 \n" + "st1 {v3.4s}, [%7], 16 \n" + "b.gt 1b \n" + : "+r"(src), // %0 + "+r"(src1), // %1 + "+r"(src2), // %2 + "+r"(src3), // %3 + "+r"(dst), // %4 + "+r"(dst1), // %5 + "+r"(dst2), // %6 + "+r"(dst3), // %7 + "+r"(width) // %8 + : "r"((ptrdiff_t)(src_stride * 4)) // %9 + : "memory", "cc", "v0", "v1", "v2", "v3"); +} + #endif // !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) #ifdef __cplusplus diff --git a/libfenrir/src/main/jni/animation/libyuv/source/row_any.cc b/libfenrir/src/main/jni/animation/libyuv/source/row_any.cc index 012f0fb29..0168061ff 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/row_any.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/row_any.cc @@ -569,7 +569,10 @@ ANY31PT(MergeXRGB16To8Row_Any_NEON, ANY21(MergeUVRow_Any_SSE2, MergeUVRow_SSE2, 0, 1, 1, 2, 15) #endif #ifdef HAS_MERGEUVROW_AVX2 -ANY21(MergeUVRow_Any_AVX2, MergeUVRow_AVX2, 0, 1, 1, 2, 31) +ANY21(MergeUVRow_Any_AVX2, MergeUVRow_AVX2, 0, 1, 1, 2, 15) +#endif +#ifdef HAS_MERGEUVROW_AVX512BW +ANY21(MergeUVRow_Any_AVX512BW, MergeUVRow_AVX512BW, 0, 1, 1, 2, 31) #endif #ifdef HAS_MERGEUVROW_NEON ANY21(MergeUVRow_Any_NEON, MergeUVRow_NEON, 0, 1, 1, 2, 15) @@ -858,7 +861,7 @@ ANY21CT(P410ToAR30Row_Any_AVX2, P410ToAR30Row_AVX2, 0, 0, uint16_t, 2, 4, 15) } #ifdef HAS_MERGEUVROW_16_AVX2 -ANY21PT(MergeUVRow_16_Any_AVX2, MergeUVRow_16_AVX2, uint16_t, 2, 15) +ANY21PT(MergeUVRow_16_Any_AVX2, MergeUVRow_16_AVX2, uint16_t, 2, 7) #endif #ifdef HAS_MERGEUVROW_16_NEON ANY21PT(MergeUVRow_16_Any_NEON, MergeUVRow_16_NEON, uint16_t, 2, 7) diff --git a/libfenrir/src/main/jni/animation/libyuv/source/row_gcc.cc b/libfenrir/src/main/jni/animation/libyuv/source/row_gcc.cc index f36d0cf01..aa4c0d11e 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/row_gcc.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/row_gcc.cc @@ -5142,36 +5142,59 @@ void DetileSplitUVRow_SSSE3(const uint8_t* src_uv, } #endif // HAS_DETILESPLITUVROW_SSSE3 +#ifdef HAS_MERGEUVROW_AVX512BW +void MergeUVRow_AVX512BW(const uint8_t* src_u, + const uint8_t* src_v, + uint8_t* dst_uv, + int width) { + asm volatile("sub %0,%1 \n" + + LABELALIGN + "1: \n" + "vpmovzxbw (%0),%%zmm0 \n" + "vpmovzxbw 0x00(%0,%1,1),%%zmm1 \n" + "lea 0x20(%0),%0 \n" + "vpsllw $0x8,%%zmm1,%%zmm1 \n" + "vporq %%zmm0,%%zmm1,%%zmm2 \n" + "vmovdqu64 %%zmm2,(%2) \n" + "lea 0x40(%2),%2 \n" + "sub $0x20,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_u), // %0 + "+r"(src_v), // %1 + "+r"(dst_uv), // %2 + "+r"(width) // %3 + : + : "memory", "cc", "xmm0", "xmm1", "xmm2"); +} +#endif // HAS_MERGEUVROW_AVX512BW + #ifdef HAS_MERGEUVROW_AVX2 void MergeUVRow_AVX2(const uint8_t* src_u, const uint8_t* src_v, uint8_t* dst_uv, int width) { - asm volatile( - - "sub %0,%1 \n" + asm volatile("sub %0,%1 \n" - LABELALIGN + LABELALIGN "1: \n" - "vmovdqu (%0),%%ymm0 \n" - "vmovdqu 0x00(%0,%1,1),%%ymm1 \n" - "lea 0x20(%0),%0 \n" - "vpunpcklbw %%ymm1,%%ymm0,%%ymm2 \n" - "vpunpckhbw %%ymm1,%%ymm0,%%ymm0 \n" - "vextractf128 $0x0,%%ymm2,(%2) \n" - "vextractf128 $0x0,%%ymm0,0x10(%2) \n" - "vextractf128 $0x1,%%ymm2,0x20(%2) \n" - "vextractf128 $0x1,%%ymm0,0x30(%2) \n" - "lea 0x40(%2),%2 \n" - "sub $0x20,%3 \n" + "vpmovzxbw (%0),%%ymm0 \n" + "vpmovzxbw 0x00(%0,%1,1),%%ymm1 \n" + "lea 0x10(%0),%0 \n" + "vpsllw $0x8,%%ymm1,%%ymm1 \n" + "vpor %%ymm0,%%ymm1,%%ymm2 \n" + "vmovdqu %%ymm2,(%2) \n" + "lea 0x20(%2),%2 \n" + "sub $0x10,%3 \n" "jg 1b \n" "vzeroupper \n" - : "+r"(src_u), // %0 - "+r"(src_v), // %1 - "+r"(dst_uv), // %2 - "+r"(width) // %3 - : - : "memory", "cc", "xmm0", "xmm1", "xmm2"); + : "+r"(src_u), // %0 + "+r"(src_v), // %1 + "+r"(dst_uv), // %2 + "+r"(width) // %3 + : + : "memory", "cc", "xmm0", "xmm1", "xmm2"); } #endif // HAS_MERGEUVROW_AVX2 @@ -5180,11 +5203,9 @@ void MergeUVRow_SSE2(const uint8_t* src_u, const uint8_t* src_v, uint8_t* dst_uv, int width) { - asm volatile( + asm volatile("sub %0,%1 \n" - "sub %0,%1 \n" - - LABELALIGN + LABELALIGN "1: \n" "movdqu (%0),%%xmm0 \n" "movdqu 0x00(%0,%1,1),%%xmm1 \n" @@ -5197,12 +5218,12 @@ void MergeUVRow_SSE2(const uint8_t* src_u, "lea 0x20(%2),%2 \n" "sub $0x10,%3 \n" "jg 1b \n" - : "+r"(src_u), // %0 - "+r"(src_v), // %1 - "+r"(dst_uv), // %2 - "+r"(width) // %3 - : - : "memory", "cc", "xmm0", "xmm1", "xmm2"); + : "+r"(src_u), // %0 + "+r"(src_v), // %1 + "+r"(dst_uv), // %2 + "+r"(width) // %3 + : + : "memory", "cc", "xmm0", "xmm1", "xmm2"); } #endif // HAS_MERGEUVROW_SSE2 @@ -5212,37 +5233,35 @@ void MergeUVRow_16_AVX2(const uint16_t* src_u, uint16_t* dst_uv, int depth, int width) { - depth = 16 - depth; // clang-format off asm volatile ( "vmovd %4,%%xmm3 \n" + "vmovd %5,%%xmm4 \n" + + "sub %0,%1 \n" + // 8 pixels per loop. - // 16 pixels per loop. - LABELALIGN + LABELALIGN "1: \n" - "vmovdqu (%0),%%ymm0 \n" - "vmovdqu (%0,%1,1),%%ymm1 \n" - "add $0x20,%0 \n" - + "vpmovzxwd (%0),%%ymm0 \n" + "vpmovzxwd 0x00(%0,%1,1),%%ymm1 \n" + "lea 0x10(%0),%0 \n" "vpsllw %%xmm3,%%ymm0,%%ymm0 \n" - "vpsllw %%xmm3,%%ymm1,%%ymm1 \n" - "vpunpcklwd %%ymm1,%%ymm0,%%ymm2 \n" // mutates - "vpunpckhwd %%ymm1,%%ymm0,%%ymm0 \n" - "vextractf128 $0x0,%%ymm2,(%2) \n" - "vextractf128 $0x0,%%ymm0,0x10(%2) \n" - "vextractf128 $0x1,%%ymm2,0x20(%2) \n" - "vextractf128 $0x1,%%ymm0,0x30(%2) \n" - "add $0x40,%2 \n" - "sub $0x10,%3 \n" + "vpslld %%xmm4,%%ymm1,%%ymm1 \n" + "vpor %%ymm0,%%ymm1,%%ymm2 \n" + "vmovdqu %%ymm2,(%2) \n" + "lea 0x20(%2),%2 \n" + "sub $0x8,%3 \n" "jg 1b \n" "vzeroupper \n" - : "+r"(src_u), // %0 - "+r"(src_v), // %1 - "+r"(dst_uv), // %2 - "+r"(width) // %3 - : "r"(depth) // %4 - : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3"); + : "+r"(src_u), // %0 + "+r"(src_v), // %1 + "+r"(dst_uv), // %2 + "+r"(width) // %3 + : "r"(16 - depth), // %4 + "r"(32 - depth) // %5 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"); // clang-format on } #endif // HAS_MERGEUVROW_AVX2 @@ -5448,7 +5467,6 @@ void Convert16To8Row_AVX2(const uint16_t* src_y, // 512 = 9 bits // 1024 = 10 bits // 4096 = 12 bits -// TODO(fbarchard): reduce to SSE2 void Convert8To16Row_SSE2(const uint8_t* src_y, uint16_t* dst_y, int scale, diff --git a/libfenrir/src/main/jni/animation/libyuv/source/row_lasx.cc b/libfenrir/src/main/jni/animation/libyuv/source/row_lasx.cc index f824906d3..29ac9254d 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/row_lasx.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/row_lasx.cc @@ -2036,8 +2036,8 @@ static void ARGBToYMatrixRow_LASX(const uint8_t* src_argb, uint8_t* dst_y, int width, const struct RgbConstants* rgbconstants) { - int32_t shuff[8] = {0, 4, 1, 5, 2, 6, 3, 7}; - asm volatile( + int32_t shuff[8] = {0, 4, 1, 5, 2, 6, 3, 7}; + asm volatile( "xvldrepl.b $xr0, %3, 0 \n\t" // load rgbconstants "xvldrepl.b $xr1, %3, 1 \n\t" // load rgbconstants "xvldrepl.b $xr2, %3, 2 \n\t" // load rgbconstants @@ -2047,19 +2047,21 @@ static void ARGBToYMatrixRow_LASX(const uint8_t* src_argb, "xvld $xr4, %0, 0 \n\t" "xvld $xr5, %0, 32 \n\t" "xvld $xr6, %0, 64 \n\t" - "xvld $xr7, %0, 96 \n\t" // load 32 pixels of ARGB + "xvld $xr7, %0, 96 \n\t" // load 32 pixels of + // ARGB "xvor.v $xr12, $xr3, $xr3 \n\t" "xvor.v $xr13, $xr3, $xr3 \n\t" - "addi.d %2, %2, -32 \n\t" // 32 processed per loop. - "xvpickev.b $xr8, $xr5, $xr4 \n\t" //BR + "addi.d %2, %2, -32 \n\t" // 32 processed per + // loop. + "xvpickev.b $xr8, $xr5, $xr4 \n\t" // BR "xvpickev.b $xr10, $xr7, $xr6 \n\t" - "xvpickod.b $xr9, $xr5, $xr4 \n\t" //GA + "xvpickod.b $xr9, $xr5, $xr4 \n\t" // GA "xvpickod.b $xr11, $xr7, $xr6 \n\t" - "xvmaddwev.h.bu $xr12, $xr8, $xr0 \n\t" //B + "xvmaddwev.h.bu $xr12, $xr8, $xr0 \n\t" // B "xvmaddwev.h.bu $xr13, $xr10, $xr0 \n\t" - "xvmaddwev.h.bu $xr12, $xr9, $xr1 \n\t" //G + "xvmaddwev.h.bu $xr12, $xr9, $xr1 \n\t" // G "xvmaddwev.h.bu $xr13, $xr11, $xr1 \n\t" - "xvmaddwod.h.bu $xr12, $xr8, $xr2 \n\t" //R + "xvmaddwod.h.bu $xr12, $xr8, $xr2 \n\t" // R "xvmaddwod.h.bu $xr13, $xr10, $xr2 \n\t" "addi.d %0, %0, 128 \n\t" "xvpickod.b $xr10, $xr13, $xr12 \n\t" @@ -2067,13 +2069,11 @@ static void ARGBToYMatrixRow_LASX(const uint8_t* src_argb, "xvst $xr11, %1, 0 \n\t" "addi.d %1, %1, 32 \n\t" "bnez %2, 1b \n\t" - : "+&r"(src_argb), // %0 - "+&r"(dst_y), // %1 - "+&r"(width) // %2 - : "r"(rgbconstants), - "r"(shuff) - : "memory" - ); + : "+&r"(src_argb), // %0 + "+&r"(dst_y), // %1 + "+&r"(width) // %2 + : "r"(rgbconstants), "r"(shuff) + : "memory"); } void ARGBToYRow_LASX(const uint8_t* src_argb, uint8_t* dst_y, int width) { @@ -2098,8 +2098,8 @@ static void RGBAToYMatrixRow_LASX(const uint8_t* src_rgba, uint8_t* dst_y, int width, const struct RgbConstants* rgbconstants) { - int32_t shuff[8] = {0, 4, 1, 5, 2, 6, 3, 7}; - asm volatile( + int32_t shuff[8] = {0, 4, 1, 5, 2, 6, 3, 7}; + asm volatile( "xvldrepl.b $xr0, %3, 0 \n\t" // load rgbconstants "xvldrepl.b $xr1, %3, 1 \n\t" // load rgbconstants "xvldrepl.b $xr2, %3, 2 \n\t" // load rgbconstants @@ -2109,19 +2109,21 @@ static void RGBAToYMatrixRow_LASX(const uint8_t* src_rgba, "xvld $xr4, %0, 0 \n\t" "xvld $xr5, %0, 32 \n\t" "xvld $xr6, %0, 64 \n\t" - "xvld $xr7, %0, 96 \n\t" // load 32 pixels of RGBA + "xvld $xr7, %0, 96 \n\t" // load 32 pixels of + // RGBA "xvor.v $xr12, $xr3, $xr3 \n\t" "xvor.v $xr13, $xr3, $xr3 \n\t" - "addi.d %2, %2, -32 \n\t" // 32 processed per loop. - "xvpickev.b $xr8, $xr5, $xr4 \n\t" //AG + "addi.d %2, %2, -32 \n\t" // 32 processed per + // loop. + "xvpickev.b $xr8, $xr5, $xr4 \n\t" // AG "xvpickev.b $xr10, $xr7, $xr6 \n\t" - "xvpickod.b $xr9, $xr5, $xr4 \n\t" //BR + "xvpickod.b $xr9, $xr5, $xr4 \n\t" // BR "xvpickod.b $xr11, $xr7, $xr6 \n\t" - "xvmaddwev.h.bu $xr12, $xr9, $xr0 \n\t" //B + "xvmaddwev.h.bu $xr12, $xr9, $xr0 \n\t" // B "xvmaddwev.h.bu $xr13, $xr11, $xr0 \n\t" - "xvmaddwod.h.bu $xr12, $xr8, $xr1 \n\t" //G + "xvmaddwod.h.bu $xr12, $xr8, $xr1 \n\t" // G "xvmaddwod.h.bu $xr13, $xr10, $xr1 \n\t" - "xvmaddwod.h.bu $xr12, $xr9, $xr2 \n\t" //R + "xvmaddwod.h.bu $xr12, $xr9, $xr2 \n\t" // R "xvmaddwod.h.bu $xr13, $xr11, $xr2 \n\t" "addi.d %0, %0, 128 \n\t" "xvpickod.b $xr10, $xr13, $xr12 \n\t" @@ -2129,13 +2131,11 @@ static void RGBAToYMatrixRow_LASX(const uint8_t* src_rgba, "xvst $xr11, %1, 0 \n\t" "addi.d %1, %1, 32 \n\t" "bnez %2, 1b \n\t" - : "+&r"(src_rgba), // %0 - "+&r"(dst_y), // %1 - "+&r"(width) // %2 - : "r"(rgbconstants), - "r"(shuff) - : "memory" - ); + : "+&r"(src_rgba), // %0 + "+&r"(dst_y), // %1 + "+&r"(width) // %2 + : "r"(rgbconstants), "r"(shuff) + : "memory"); } void RGBAToYRow_LASX(const uint8_t* src_rgba, uint8_t* dst_y, int width) { @@ -2151,18 +2151,19 @@ void BGRAToYRow_LASX(const uint8_t* src_bgra, uint8_t* dst_y, int width) { } static void RGBToYMatrixRow_LASX(const uint8_t* src_rgba, - uint8_t* dst_y, - int width, - const struct RgbConstants* rgbconstants) { - int8_t shuff[128] = {0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, - 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, - 24, 26, 27, 29, 30, 0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, - 24, 26, 27, 29, 30, 0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, - 1, 0, 4, 0, 7, 0, 10, 0, 13, 0, 16, 0, 19, 0, 22, 0, - 1, 0, 4, 0, 7, 0, 10, 0, 13, 0, 16, 0, 19, 0, 22, 0, - 25, 0, 28, 0, 31, 0, 2, 0, 5, 0, 8, 0, 11, 0, 14, 0, - 25, 0, 28, 0, 31, 0, 2, 0, 5, 0, 8, 0, 11, 0, 14, 0}; - asm volatile( + uint8_t* dst_y, + int width, + const struct RgbConstants* rgbconstants) { + int8_t shuff[128] = { + 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, + 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, + 24, 26, 27, 29, 30, 0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, + 24, 26, 27, 29, 30, 0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, + 1, 0, 4, 0, 7, 0, 10, 0, 13, 0, 16, 0, 19, 0, 22, 0, + 1, 0, 4, 0, 7, 0, 10, 0, 13, 0, 16, 0, 19, 0, 22, 0, + 25, 0, 28, 0, 31, 0, 2, 0, 5, 0, 8, 0, 11, 0, 14, 0, + 25, 0, 28, 0, 31, 0, 2, 0, 5, 0, 8, 0, 11, 0, 14, 0}; + asm volatile( "xvldrepl.b $xr0, %3, 0 \n\t" // load rgbconstants "xvldrepl.b $xr1, %3, 1 \n\t" // load rgbconstants "xvldrepl.b $xr2, %3, 2 \n\t" // load rgbconstants @@ -2174,23 +2175,25 @@ static void RGBToYMatrixRow_LASX(const uint8_t* src_rgba, "1: \n\t" "xvld $xr8, %0, 0 \n\t" "xvld $xr9, %0, 32 \n\t" - "xvld $xr10, %0, 64 \n\t" // load 32 pixels of RGB + "xvld $xr10, %0, 64 \n\t" // load 32 pixels of + // RGB "xvor.v $xr12, $xr3, $xr3 \n\t" "xvor.v $xr13, $xr3, $xr3 \n\t" "xvor.v $xr11, $xr9, $xr9 \n\t" - "addi.d %2, %2, -32 \n\t" // 32 processed per loop. - "xvpermi.q $xr9, $xr8, 0x30 \n\t" //src0 - "xvpermi.q $xr8, $xr10, 0x03 \n\t" //src1 - "xvpermi.q $xr10, $xr11, 0x30 \n\t" //src2 + "addi.d %2, %2, -32 \n\t" // 32 processed per + // loop. + "xvpermi.q $xr9, $xr8, 0x30 \n\t" // src0 + "xvpermi.q $xr8, $xr10, 0x03 \n\t" // src1 + "xvpermi.q $xr10, $xr11, 0x30 \n\t" // src2 "xvshuf.b $xr14, $xr8, $xr9, $xr4 \n\t" "xvshuf.b $xr15, $xr8, $xr10, $xr5 \n\t" "xvshuf.b $xr16, $xr8, $xr9, $xr6 \n\t" "xvshuf.b $xr17, $xr8, $xr10, $xr7 \n\t" - "xvmaddwev.h.bu $xr12, $xr16, $xr1 \n\t" //G + "xvmaddwev.h.bu $xr12, $xr16, $xr1 \n\t" // G "xvmaddwev.h.bu $xr13, $xr17, $xr1 \n\t" - "xvmaddwev.h.bu $xr12, $xr14, $xr0 \n\t" //B + "xvmaddwev.h.bu $xr12, $xr14, $xr0 \n\t" // B "xvmaddwev.h.bu $xr13, $xr15, $xr0 \n\t" - "xvmaddwod.h.bu $xr12, $xr14, $xr2 \n\t" //R + "xvmaddwod.h.bu $xr12, $xr14, $xr2 \n\t" // R "xvmaddwod.h.bu $xr13, $xr15, $xr2 \n\t" "addi.d %0, %0, 96 \n\t" "xvpickod.b $xr10, $xr13, $xr12 \n\t" @@ -2202,8 +2205,7 @@ static void RGBToYMatrixRow_LASX(const uint8_t* src_rgba, "+&r"(width) // %2 : "r"(rgbconstants), // %3 "r"(shuff) // %4 - : "memory" - ); + : "memory"); } void RGB24ToYJRow_LASX(const uint8_t* src_rgb24, uint8_t* dst_yj, int width) { diff --git a/libfenrir/src/main/jni/animation/libyuv/source/row_lsx.cc b/libfenrir/src/main/jni/animation/libyuv/source/row_lsx.cc index 0825b6335..9c1e16f22 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/row_lsx.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/row_lsx.cc @@ -1679,7 +1679,7 @@ static void ARGBToYMatrixRow_LSX(const uint8_t* src_argb, uint8_t* dst_y, int width, const struct RgbConstants* rgbconstants) { - asm volatile( + asm volatile( "vldrepl.b $vr0, %3, 0 \n\t" // load rgbconstants "vldrepl.b $vr1, %3, 1 \n\t" // load rgbconstants "vldrepl.b $vr2, %3, 2 \n\t" // load rgbconstants @@ -1688,31 +1688,32 @@ static void ARGBToYMatrixRow_LSX(const uint8_t* src_argb, "vld $vr4, %0, 0 \n\t" "vld $vr5, %0, 16 \n\t" "vld $vr6, %0, 32 \n\t" - "vld $vr7, %0, 48 \n\t" // load 16 pixels of ARGB + "vld $vr7, %0, 48 \n\t" // load 16 pixels of + // ARGB "vor.v $vr12, $vr3, $vr3 \n\t" "vor.v $vr13, $vr3, $vr3 \n\t" - "addi.d %2, %2, -16 \n\t" // 16 processed per loop. - "vpickev.b $vr8, $vr5, $vr4 \n\t" //BR + "addi.d %2, %2, -16 \n\t" // 16 processed per + // loop. + "vpickev.b $vr8, $vr5, $vr4 \n\t" // BR "vpickev.b $vr10, $vr7, $vr6 \n\t" - "vpickod.b $vr9, $vr5, $vr4 \n\t" //GA + "vpickod.b $vr9, $vr5, $vr4 \n\t" // GA "vpickod.b $vr11, $vr7, $vr6 \n\t" - "vmaddwev.h.bu $vr12, $vr8, $vr0 \n\t" //B + "vmaddwev.h.bu $vr12, $vr8, $vr0 \n\t" // B "vmaddwev.h.bu $vr13, $vr10, $vr0 \n\t" - "vmaddwev.h.bu $vr12, $vr9, $vr1 \n\t" //G + "vmaddwev.h.bu $vr12, $vr9, $vr1 \n\t" // G "vmaddwev.h.bu $vr13, $vr11, $vr1 \n\t" - "vmaddwod.h.bu $vr12, $vr8, $vr2 \n\t" //R + "vmaddwod.h.bu $vr12, $vr8, $vr2 \n\t" // R "vmaddwod.h.bu $vr13, $vr10, $vr2 \n\t" "addi.d %0, %0, 64 \n\t" "vpickod.b $vr10, $vr13, $vr12 \n\t" "vst $vr10, %1, 0 \n\t" "addi.d %1, %1, 16 \n\t" "bnez %2, 1b \n\t" - : "+&r"(src_argb), // %0 - "+&r"(dst_y), // %1 - "+&r"(width) // %2 + : "+&r"(src_argb), // %0 + "+&r"(dst_y), // %1 + "+&r"(width) // %2 : "r"(rgbconstants) - : "memory" - ); + : "memory"); } void ARGBToYRow_LSX(const uint8_t* src_argb, uint8_t* dst_y, int width) { @@ -1737,7 +1738,7 @@ static void RGBAToYMatrixRow_LSX(const uint8_t* src_rgba, uint8_t* dst_y, int width, const struct RgbConstants* rgbconstants) { - asm volatile( + asm volatile( "vldrepl.b $vr0, %3, 0 \n\t" // load rgbconstants "vldrepl.b $vr1, %3, 1 \n\t" // load rgbconstants "vldrepl.b $vr2, %3, 2 \n\t" // load rgbconstants @@ -1746,31 +1747,32 @@ static void RGBAToYMatrixRow_LSX(const uint8_t* src_rgba, "vld $vr4, %0, 0 \n\t" "vld $vr5, %0, 16 \n\t" "vld $vr6, %0, 32 \n\t" - "vld $vr7, %0, 48 \n\t" // load 16 pixels of RGBA + "vld $vr7, %0, 48 \n\t" // load 16 pixels of + // RGBA "vor.v $vr12, $vr3, $vr3 \n\t" "vor.v $vr13, $vr3, $vr3 \n\t" - "addi.d %2, %2, -16 \n\t" // 16 processed per loop. - "vpickev.b $vr8, $vr5, $vr4 \n\t" //AG + "addi.d %2, %2, -16 \n\t" // 16 processed per + // loop. + "vpickev.b $vr8, $vr5, $vr4 \n\t" // AG "vpickev.b $vr10, $vr7, $vr6 \n\t" - "vpickod.b $vr9, $vr5, $vr4 \n\t" //BR + "vpickod.b $vr9, $vr5, $vr4 \n\t" // BR "vpickod.b $vr11, $vr7, $vr6 \n\t" - "vmaddwev.h.bu $vr12, $vr9, $vr0 \n\t" //B + "vmaddwev.h.bu $vr12, $vr9, $vr0 \n\t" // B "vmaddwev.h.bu $vr13, $vr11, $vr0 \n\t" - "vmaddwod.h.bu $vr12, $vr8, $vr1 \n\t" //G + "vmaddwod.h.bu $vr12, $vr8, $vr1 \n\t" // G "vmaddwod.h.bu $vr13, $vr10, $vr1 \n\t" - "vmaddwod.h.bu $vr12, $vr9, $vr2 \n\t" //R + "vmaddwod.h.bu $vr12, $vr9, $vr2 \n\t" // R "vmaddwod.h.bu $vr13, $vr11, $vr2 \n\t" "addi.d %0, %0, 64 \n\t" "vpickod.b $vr10, $vr13, $vr12 \n\t" "vst $vr10, %1, 0 \n\t" "addi.d %1, %1, 16 \n\t" "bnez %2, 1b \n\t" - : "+&r"(src_rgba), // %0 - "+&r"(dst_y), // %1 - "+&r"(width) // %2 + : "+&r"(src_rgba), // %0 + "+&r"(dst_y), // %1 + "+&r"(width) // %2 : "r"(rgbconstants) - : "memory" - ); + : "memory"); } void RGBAToYRow_LSX(const uint8_t* src_rgba, uint8_t* dst_y, int width) { @@ -1789,11 +1791,12 @@ static void RGBToYMatrixRow_LSX(const uint8_t* src_rgba, uint8_t* dst_y, int width, const struct RgbConstants* rgbconstants) { - int8_t shuff[64] = {0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, - 24, 26, 27, 29, 30, 0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, - 1, 0, 4, 0, 7, 0, 10, 0, 13, 0, 16, 0, 19, 0, 22, 0, - 25, 0, 28, 0, 31, 0, 2, 0, 5, 0, 8, 0, 11, 0, 14, 0}; - asm volatile( + int8_t shuff[64] = {0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, + 20, 21, 23, 24, 26, 27, 29, 30, 0, 1, 3, 4, 6, + 7, 9, 10, 12, 13, 15, 1, 0, 4, 0, 7, 0, 10, + 0, 13, 0, 16, 0, 19, 0, 22, 0, 25, 0, 28, 0, + 31, 0, 2, 0, 5, 0, 8, 0, 11, 0, 14, 0}; + asm volatile( "vldrepl.b $vr0, %3, 0 \n\t" // load rgbconstants "vldrepl.b $vr1, %3, 1 \n\t" // load rgbconstants "vldrepl.b $vr2, %3, 2 \n\t" // load rgbconstants @@ -1805,19 +1808,21 @@ static void RGBToYMatrixRow_LSX(const uint8_t* src_rgba, "1: \n\t" "vld $vr8, %0, 0 \n\t" "vld $vr9, %0, 16 \n\t" - "vld $vr10, %0, 32 \n\t" // load 16 pixels of RGB + "vld $vr10, %0, 32 \n\t" // load 16 pixels of + // RGB "vor.v $vr12, $vr3, $vr3 \n\t" "vor.v $vr13, $vr3, $vr3 \n\t" - "addi.d %2, %2, -16 \n\t" // 16 processed per loop. + "addi.d %2, %2, -16 \n\t" // 16 processed per + // loop. "vshuf.b $vr14, $vr9, $vr8, $vr4 \n\t" "vshuf.b $vr15, $vr9, $vr10, $vr5 \n\t" "vshuf.b $vr16, $vr9, $vr8, $vr6 \n\t" "vshuf.b $vr17, $vr9, $vr10, $vr7 \n\t" - "vmaddwev.h.bu $vr12, $vr16, $vr1 \n\t" //G + "vmaddwev.h.bu $vr12, $vr16, $vr1 \n\t" // G "vmaddwev.h.bu $vr13, $vr17, $vr1 \n\t" - "vmaddwev.h.bu $vr12, $vr14, $vr0 \n\t" //B + "vmaddwev.h.bu $vr12, $vr14, $vr0 \n\t" // B "vmaddwev.h.bu $vr13, $vr15, $vr0 \n\t" - "vmaddwod.h.bu $vr12, $vr14, $vr2 \n\t" //R + "vmaddwod.h.bu $vr12, $vr14, $vr2 \n\t" // R "vmaddwod.h.bu $vr13, $vr15, $vr2 \n\t" "addi.d %0, %0, 48 \n\t" "vpickod.b $vr10, $vr13, $vr12 \n\t" @@ -1829,8 +1834,7 @@ static void RGBToYMatrixRow_LSX(const uint8_t* src_rgba, "+&r"(width) // %2 : "r"(rgbconstants), // %3 "r"(shuff) // %4 - : "memory" - ); + : "memory"); } void RGB24ToYJRow_LSX(const uint8_t* src_rgb24, uint8_t* dst_yj, int width) { diff --git a/libfenrir/src/main/jni/animation/libyuv/source/scale.cc b/libfenrir/src/main/jni/animation/libyuv/source/scale.cc index 65a4685fc..830754ce6 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/scale.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/scale.cc @@ -1065,10 +1065,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, @@ -1188,10 +1188,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, @@ -1276,10 +1276,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, @@ -1744,10 +1744,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, @@ -1872,7 +1872,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; @@ -1909,7 +1909,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_common.cc b/libfenrir/src/main/jni/animation/libyuv/source/scale_common.cc index f18324034..da9ca713e 100644 --- a/libfenrir/src/main/jni/animation/libyuv/source/scale_common.cc +++ b/libfenrir/src/main/jni/animation/libyuv/source/scale_common.cc @@ -1633,7 +1633,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; @@ -1712,7 +1712,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; @@ -1791,7 +1791,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/compress/zstd/common/error_private.c b/libfenrir/src/main/jni/compress/zstd/common/error_private.c index 0cff6b80b..075fc5ef4 100644 --- a/libfenrir/src/main/jni/compress/zstd/common/error_private.c +++ b/libfenrir/src/main/jni/compress/zstd/common/error_private.c @@ -54,7 +54,7 @@ const char* ERR_getErrorString(ERR_enum code) case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; - case PREFIX(externalMatchFinder_failed): return "External matchfinder returned an error code"; + case PREFIX(sequenceProducer_failed): return "Block-level external sequence producer returned an error code"; case PREFIX(externalSequences_invalid): return "External sequences are not valid"; case PREFIX(maxCode): default: return notErrorCode; 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 5b89ca6d2..b55f684cd 100644 --- a/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress.c +++ b/libfenrir/src/main/jni/compress/zstd/compress/zstd_compress.c @@ -615,7 +615,7 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) bounds.upperBound = (int)ZSTD_ps_disable; return bounds; - case ZSTD_c_enableMatchFinderFallback: + case ZSTD_c_enableSeqProducerFallback: bounds.lowerBound = 0; bounds.upperBound = 1; return bounds; @@ -695,7 +695,7 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_useRowMatchFinder: case ZSTD_c_deterministicRefPrefix: case ZSTD_c_prefetchCDictTables: - case ZSTD_c_enableMatchFinderFallback: + case ZSTD_c_enableSeqProducerFallback: case ZSTD_c_maxBlockSize: case ZSTD_c_searchForExternalRepcodes: default: @@ -754,7 +754,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) case ZSTD_c_useRowMatchFinder: case ZSTD_c_deterministicRefPrefix: case ZSTD_c_prefetchCDictTables: - case ZSTD_c_enableMatchFinderFallback: + case ZSTD_c_enableSeqProducerFallback: case ZSTD_c_maxBlockSize: case ZSTD_c_searchForExternalRepcodes: break; @@ -989,8 +989,8 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, CCtxParams->prefetchCDictTables = (ZSTD_paramSwitch_e)value; return CCtxParams->prefetchCDictTables; - case ZSTD_c_enableMatchFinderFallback: - BOUNDCHECK(ZSTD_c_enableMatchFinderFallback, value); + case ZSTD_c_enableSeqProducerFallback: + BOUNDCHECK(ZSTD_c_enableSeqProducerFallback, value); CCtxParams->enableMatchFinderFallback = value; return CCtxParams->enableMatchFinderFallback; @@ -1140,7 +1140,7 @@ size_t ZSTD_CCtxParams_getParameter( case ZSTD_c_prefetchCDictTables: *value = (int)CCtxParams->prefetchCDictTables; break; - case ZSTD_c_enableMatchFinderFallback: + case ZSTD_c_enableSeqProducerFallback: *value = CCtxParams->enableMatchFinderFallback; break; case ZSTD_c_maxBlockSize: @@ -1610,8 +1610,8 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, /* Helper function for calculating memory requirements. * Gives a tighter bound than ZSTD_sequenceBound() by taking minMatch into account. */ -static size_t ZSTD_maxNbSeq(size_t blockSize, unsigned minMatch, int useExternalMatchFinder) { - U32 const divider = (minMatch==3 || useExternalMatchFinder) ? 3 : 4; +static size_t ZSTD_maxNbSeq(size_t blockSize, unsigned minMatch, int useSequenceProducer) { + U32 const divider = (minMatch==3 || useSequenceProducer) ? 3 : 4; return blockSize / divider; } @@ -1623,12 +1623,12 @@ static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( const size_t buffInSize, const size_t buffOutSize, const U64 pledgedSrcSize, - int useExternalMatchFinder, + int useSequenceProducer, size_t maxBlockSize) { size_t const windowSize = (size_t) BOUNDED(1ULL, 1ULL << cParams->windowLog, pledgedSrcSize); size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(maxBlockSize), windowSize); - size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, cParams->minMatch, useExternalMatchFinder); + size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, cParams->minMatch, useSequenceProducer); size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) + ZSTD_cwksp_aligned_alloc_size(maxNbSeq * sizeof(seqDef)) + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); @@ -1648,7 +1648,7 @@ static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); - size_t const externalSeqSpace = useExternalMatchFinder + size_t const externalSeqSpace = useSequenceProducer ? ZSTD_cwksp_aligned_alloc_size(maxNbExternalSeq * sizeof(ZSTD_Sequence)) : 0; @@ -1679,7 +1679,7 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) * be needed. However, we still allocate two 0-sized buffers, which can * take space under ASAN. */ return ZSTD_estimateCCtxSize_usingCCtxParams_internal( - &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, params->useExternalMatchFinder, params->maxBlockSize); + &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, params->useSequenceProducer, params->maxBlockSize); } size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) @@ -1740,7 +1740,7 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) return ZSTD_estimateCCtxSize_usingCCtxParams_internal( &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, - ZSTD_CONTENTSIZE_UNKNOWN, params->useExternalMatchFinder, params->maxBlockSize); + ZSTD_CONTENTSIZE_UNKNOWN, params->useSequenceProducer, params->maxBlockSize); } } @@ -2024,7 +2024,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize)); size_t const blockSize = MIN(params->maxBlockSize, windowSize); - size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, params->useExternalMatchFinder); + size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, params->useSequenceProducer); size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered) ? ZSTD_compressBound(blockSize) + 1 : 0; @@ -2041,7 +2041,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, size_t const neededSpace = ZSTD_estimateCCtxSize_usingCCtxParams_internal( ¶ms->cParams, ¶ms->ldmParams, zc->staticSize != 0, params->useRowMatchFinder, - buffInSize, buffOutSize, pledgedSrcSize, params->useExternalMatchFinder, params->maxBlockSize); + buffInSize, buffOutSize, pledgedSrcSize, params->useSequenceProducer, params->maxBlockSize); int resizeWorkspace; FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!"); @@ -2155,7 +2155,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, } /* reserve space for block-level external sequences */ - if (params->useExternalMatchFinder) { + if (params->useSequenceProducer) { size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); zc->externalMatchCtx.seqBufferCapacity = maxNbExternalSeq; zc->externalMatchCtx.seqBuffer = @@ -3022,26 +3022,26 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr) ssPtr->longLengthType = ZSTD_llt_none; } -/* ZSTD_postProcessExternalMatchFinderResult() : +/* ZSTD_postProcessSequenceProducerResult() : * Validates and post-processes sequences obtained through the external matchfinder API: * - Checks whether nbExternalSeqs represents an error condition. * - Appends a block delimiter to outSeqs if one is not already present. * See zstd.h for context regarding block delimiters. * Returns the number of sequences after post-processing, or an error code. */ -static size_t ZSTD_postProcessExternalMatchFinderResult( +static size_t ZSTD_postProcessSequenceProducerResult( ZSTD_Sequence* outSeqs, size_t nbExternalSeqs, size_t outSeqsCapacity, size_t srcSize ) { RETURN_ERROR_IF( nbExternalSeqs > outSeqsCapacity, - externalMatchFinder_failed, - "External matchfinder returned error code %lu", + sequenceProducer_failed, + "External sequence producer returned error code %lu", (unsigned long)nbExternalSeqs ); RETURN_ERROR_IF( nbExternalSeqs == 0 && srcSize > 0, - externalMatchFinder_failed, - "External matchfinder produced zero sequences for a non-empty src buffer!" + sequenceProducer_failed, + "Got zero sequences from external sequence producer for a non-empty src buffer!" ); if (srcSize == 0) { @@ -3061,7 +3061,7 @@ static size_t ZSTD_postProcessExternalMatchFinderResult( * produced an invalid parse, by definition of ZSTD_sequenceBound(). */ RETURN_ERROR_IF( nbExternalSeqs == outSeqsCapacity, - externalMatchFinder_failed, + sequenceProducer_failed, "nbExternalSeqs == outSeqsCapacity but lastSeq is not a block delimiter!" ); @@ -3139,9 +3139,9 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) /* External matchfinder + LDM is technically possible, just not implemented yet. * We need to revisit soon and implement it. */ RETURN_ERROR_IF( - zc->appliedParams.useExternalMatchFinder, + zc->appliedParams.useSequenceProducer, parameter_combination_unsupported, - "Long-distance matching with external matchfinder enabled is not currently supported." + "Long-distance matching with external sequence producer enabled is not currently supported." ); /* Updates ldmSeqStore.pos */ @@ -3158,9 +3158,9 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) /* External matchfinder + LDM is technically possible, just not implemented yet. * We need to revisit soon and implement it. */ RETURN_ERROR_IF( - zc->appliedParams.useExternalMatchFinder, + zc->appliedParams.useSequenceProducer, parameter_combination_unsupported, - "Long-distance matching with external matchfinder enabled is not currently supported." + "Long-distance matching with external sequence producer enabled is not currently supported." ); ldmSeqStore.seq = zc->ldmSequences; @@ -3177,7 +3177,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) zc->appliedParams.useRowMatchFinder, src, srcSize); assert(ldmSeqStore.pos == ldmSeqStore.size); - } else if (zc->appliedParams.useExternalMatchFinder) { + } else if (zc->appliedParams.useSequenceProducer) { assert( zc->externalMatchCtx.seqBufferCapacity >= ZSTD_sequenceBound(srcSize) ); @@ -3195,7 +3195,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) windowSize ); - size_t const nbPostProcessedSeqs = ZSTD_postProcessExternalMatchFinderResult( + size_t const nbPostProcessedSeqs = ZSTD_postProcessSequenceProducerResult( zc->externalMatchCtx.seqBuffer, nbExternalSeqs, zc->externalMatchCtx.seqBufferCapacity, @@ -3217,7 +3217,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) "Failed to copy external sequences to seqStore!" ); ms->ldmSeqStore = NULL; - DEBUGLOG(5, "Copied %lu sequences from external matchfinder to internal seqStore.", (unsigned long)nbExternalSeqs); + DEBUGLOG(5, "Copied %lu sequences from external sequence producer to internal seqStore.", (unsigned long)nbExternalSeqs); return ZSTDbss_compress; } @@ -3233,7 +3233,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) ms->ldmSeqStore = NULL; DEBUGLOG( 5, - "External matchfinder returned error code %lu. Falling back to internal matchfinder.", + "External sequence producer returned error code %lu. Falling back to internal parser.", (unsigned long)nbExternalSeqs ); lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); @@ -6033,9 +6033,9 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx, #ifdef ZSTD_MULTITHREAD /* If external matchfinder is enabled, make sure to fail before checking job size (for consistency) */ RETURN_ERROR_IF( - params.useExternalMatchFinder == 1 && params.nbWorkers >= 1, + params.useSequenceProducer == 1 && params.nbWorkers >= 1, parameter_combination_unsupported, - "External matchfinder isn't supported with nbWorkers >= 1" + "External sequence producer isn't supported with nbWorkers >= 1" ); if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { @@ -6251,7 +6251,7 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx, */ static size_t ZSTD_validateSequence(U32 offCode, U32 matchLength, U32 minMatch, - size_t posInSrc, U32 windowLog, size_t dictSize, int useExternalMatchFinder) + size_t posInSrc, U32 windowLog, size_t dictSize, int useSequenceProducer) { U32 const windowSize = 1u << windowLog; /* posInSrc represents the amount of data the decoder would decode up to this point. @@ -6260,7 +6260,7 @@ ZSTD_validateSequence(U32 offCode, U32 matchLength, U32 minMatch, * window size. After output surpasses windowSize, we're limited to windowSize offsets again. */ size_t const offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize; - size_t const matchLenLowerBound = (minMatch == 3 || useExternalMatchFinder) ? 3 : 4; + size_t const matchLenLowerBound = (minMatch == 3 || useSequenceProducer) ? 3 : 4; RETURN_ERROR_IF(offCode > OFFSET_TO_OFFBASE(offsetBound), externalSequences_invalid, "Offset too large!"); /* Validate maxNbSeq is large enough for the given matchLength and minMatch */ RETURN_ERROR_IF(matchLength < matchLenLowerBound, externalSequences_invalid, "Matchlength too small for the minMatch"); @@ -6325,7 +6325,7 @@ ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, if (cctx->appliedParams.validateSequences) { seqPos->posInSrc += litLength + matchLength; FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, - cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useExternalMatchFinder), + cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useSequenceProducer), "Sequence validation failed"); } RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, @@ -6463,7 +6463,7 @@ ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* if (cctx->appliedParams.validateSequences) { seqPos->posInSrc += litLength + matchLength; FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, - cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useExternalMatchFinder), + cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useSequenceProducer), "Sequence validation failed"); } DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); @@ -6908,9 +6908,9 @@ ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeH return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); } -void ZSTD_registerExternalMatchFinder( +void ZSTD_registerSequenceProducer( ZSTD_CCtx* zc, void* mState, - ZSTD_externalMatchFinder_F* mFinder + ZSTD_sequenceProducer_F* mFinder ) { if (mFinder != NULL) { ZSTD_externalMatchCtx emctx; @@ -6919,9 +6919,9 @@ void ZSTD_registerExternalMatchFinder( emctx.seqBuffer = NULL; emctx.seqBufferCapacity = 0; zc->externalMatchCtx = emctx; - zc->requestedParams.useExternalMatchFinder = 1; + zc->requestedParams.useSequenceProducer = 1; } else { ZSTD_memset(&zc->externalMatchCtx, 0, sizeof(zc->externalMatchCtx)); - zc->requestedParams.useExternalMatchFinder = 0; + zc->requestedParams.useSequenceProducer = 0; } } 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 dac7a0aa2..cbb85e527 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 @@ -353,8 +353,8 @@ struct ZSTD_CCtx_params_s { /* Indicates whether an external matchfinder has been referenced. * Users can't set this externally. - * It is set internally in ZSTD_registerExternalMatchFinder(). */ - int useExternalMatchFinder; + * It is set internally in ZSTD_registerSequenceProducer(). */ + int useSequenceProducer; /* Adjust the max block size*/ size_t maxBlockSize; @@ -395,7 +395,7 @@ typedef struct { /* Context for block-level external matchfinder API */ typedef struct { void* mState; - ZSTD_externalMatchFinder_F* mFinder; + ZSTD_sequenceProducer_F* mFinder; ZSTD_Sequence* seqBuffer; size_t seqBufferCapacity; } ZSTD_externalMatchCtx; diff --git a/libfenrir/src/main/jni/compress/zstd/zstd.h b/libfenrir/src/main/jni/compress/zstd/zstd.h index 91a3679a1..95aac0737 100644 --- a/libfenrir/src/main/jni/compress/zstd/zstd.h +++ b/libfenrir/src/main/jni/compress/zstd/zstd.h @@ -478,7 +478,7 @@ typedef enum { * ZSTD_c_useBlockSplitter * ZSTD_c_useRowMatchFinder * ZSTD_c_prefetchCDictTables - * ZSTD_c_enableMatchFinderFallback + * ZSTD_c_enableSeqProducerFallback * ZSTD_c_maxBlockSize * Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them. * note : never ever use experimentalParam? names directly; @@ -565,7 +565,7 @@ typedef enum { * They will be used to compress next frame. * Resetting session never fails. * - The parameters : changes all parameters back to "default". - * This also removes any reference to any dictionary or external matchfinder. + * This also removes any reference to any dictionary or external sequence producer. * Parameters can only be changed between 2 sessions (i.e. no compression is currently ongoing) * otherwise the reset fails, and function returns an error value (which can be tested using ZSTD_isError()) * - Both : similar to resetting the session, followed by resetting parameters. @@ -1627,8 +1627,8 @@ ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size); * Note : only single-threaded compression is supported. * ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. * - * Note 2 : ZSTD_estimateCCtxSize* functions are not compatible with the external matchfinder API at this time. - * Size estimates assume that no external matchfinder is registered. + * Note 2 : ZSTD_estimateCCtxSize* functions are not compatible with the Block-Level Sequence Producer API at this time. + * Size estimates assume that no external sequence producer is registered. */ ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int compressionLevel); ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams); @@ -1650,8 +1650,8 @@ ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void); * In this case, get total size by adding ZSTD_estimate?DictSize * Note 2 : only single-threaded compression is supported. * ZSTD_estimateCStreamSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1. - * Note 3 : ZSTD_estimateCStreamSize* functions are not compatible with the external matchfinder API at this time. - * Size estimates assume that no external matchfinder is registered. + * Note 3 : ZSTD_estimateCStreamSize* functions are not compatible with the Block-Level Sequence Producer API at this time. + * Size estimates assume that no external sequence producer is registered. */ ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int compressionLevel); ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams); @@ -2113,19 +2113,19 @@ ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const vo */ #define ZSTD_c_prefetchCDictTables ZSTD_c_experimentalParam16 -/* ZSTD_c_enableMatchFinderFallback +/* ZSTD_c_enableSeqProducerFallback * Allowed values are 0 (disable) and 1 (enable). The default setting is 0. * - * Controls whether zstd will fall back to an internal matchfinder if an - * external matchfinder is registered and returns an error code. This fallback is - * block-by-block: the internal matchfinder will only be called for blocks where - * the external matchfinder returns an error code. Fallback compression will + * Controls whether zstd will fall back to an internal sequence producer if an + * external sequence producer is registered and returns an error code. This fallback + * is block-by-block: the internal sequence producer will only be called for blocks + * where the external sequence producer returns an error code. Fallback parsing will * follow any other cParam settings, such as compression level, the same as in a * normal (fully-internal) compression operation. * - * The user is strongly encouraged to read the full external matchfinder API + * The user is strongly encouraged to read the full Block-Level Sequence Producer API * documentation (below) before setting this parameter. */ -#define ZSTD_c_enableMatchFinderFallback ZSTD_c_experimentalParam17 +#define ZSTD_c_enableSeqProducerFallback ZSTD_c_experimentalParam17 /* ZSTD_c_maxBlockSize * Allowed values are between 1KB and ZSTD_BLOCKSIZE_MAX (128KB). @@ -2141,12 +2141,13 @@ ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const vo /* ZSTD_c_searchForExternalRepcodes * This parameter affects how zstd parses external sequences, such as sequences - * provided through the compressSequences() API or from an external matchfinder. + * provided through the compressSequences() API or from an external block-level + * sequence producer. * * If set to ZSTD_ps_enable, the library will check for repeated offsets in * external sequences, even if those repcodes are not explicitly indicated in * the "rep" field. Note that this is the only way to exploit repcode matches - * while using compressSequences() or an external matchfinder, since zstd + * while using compressSequences() or an external sequence producer, since zstd * currently ignores the "rep" field of external sequences. * * If set to ZSTD_ps_disable, the library will not exploit repeated offsets in @@ -2805,43 +2806,52 @@ ZSTDLIB_STATIC_API size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_ ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize); /**< insert uncompressed block into `dctx` history. Useful for multi-blocks decompression. */ -/* ********************** EXTERNAL MATCHFINDER API ********************** +/* ********************* BLOCK-LEVEL SEQUENCE PRODUCER API ********************* * * *** OVERVIEW *** - * This API allows users to replace the zstd internal block-level matchfinder - * with an external matchfinder function. Potential applications of the API - * include hardware-accelerated matchfinders and matchfinders specialized to - * particular types of data. - * - * See contrib/externalMatchfinder for an example program employing the - * external matchfinder API. + * The Block-Level Sequence Producer API allows users to provide their own custom + * sequence producer which libzstd invokes to process each block. The produced list + * of sequences (literals and matches) is then post-processed by libzstd to produce + * valid compressed blocks. + * + * This block-level offload API is a more granular complement of the existing + * frame-level offload API compressSequences() (introduced in v1.5.1). It offers + * an easier migration story for applications already integrated with libzstd: the + * user application continues to invoke the same compression functions + * ZSTD_compress2() or ZSTD_compressStream2() as usual, and transparently benefits + * from the specific advantages of the external sequence producer. For example, + * the sequence producer could be tuned to take advantage of known characteristics + * of the input, to offer better speed / ratio, or could leverage hardware + * acceleration not available within libzstd itself. + * + * See contrib/externalSequenceProducer for an example program employing the + * Block-Level Sequence Producer API. * * *** USAGE *** * The user is responsible for implementing a function of type - * ZSTD_externalMatchFinder_F. For each block, zstd will pass the following + * ZSTD_sequenceProducer_F. For each block, zstd will pass the following * arguments to the user-provided function: * - * - externalMatchState: a pointer to a user-managed state for the external - * matchfinder. + * - sequenceProducerState: a pointer to a user-managed state for the sequence + * producer. * - * - outSeqs, outSeqsCapacity: an output buffer for sequences produced by the - * external matchfinder. outSeqsCapacity is guaranteed >= - * ZSTD_sequenceBound(srcSize). The memory backing outSeqs is managed by - * the CCtx. + * - outSeqs, outSeqsCapacity: an output buffer for the sequence producer. + * outSeqsCapacity is guaranteed >= ZSTD_sequenceBound(srcSize). The memory + * backing outSeqs is managed by the CCtx. * - * - src, srcSize: an input buffer which the external matchfinder must parse - * into sequences. srcSize is guaranteed to be <= ZSTD_BLOCKSIZE_MAX. + * - src, srcSize: an input buffer for the sequence producer to parse. + * srcSize is guaranteed to be <= ZSTD_BLOCKSIZE_MAX. * - * - dict, dictSize: a history buffer, which may be empty, which the external - * matchfinder may reference as it produces sequences for the src buffer. - * Currently, zstd will always pass dictSize == 0 into external matchfinders, - * but this will change in the future. + * - dict, dictSize: a history buffer, which may be empty, which the sequence + * producer may reference as it parses the src buffer. Currently, zstd will + * always pass dictSize == 0 into external sequence producers, but this will + * change in the future. * * - compressionLevel: a signed integer representing the zstd compression level - * set by the user for the current operation. The external matchfinder may - * choose to use this information to change its compression strategy and - * speed/ratio tradeoff. Note: The compression level does not reflect zstd - * parameters set through the advanced API. + * set by the user for the current operation. The sequence producer may choose + * to use this information to change its compression strategy and speed/ratio + * tradeoff. Note: the compression level does not reflect zstd parameters set + * through the advanced API. * * - windowSize: a size_t representing the maximum allowed offset for external * sequences. Note that sequence offsets are sometimes allowed to exceed the @@ -2851,7 +2861,7 @@ ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* bloc * The user-provided function shall return a size_t representing the number of * sequences written to outSeqs. This return value will be treated as an error * code if it is greater than outSeqsCapacity. The return value must be non-zero - * if srcSize is non-zero. The ZSTD_EXTERNAL_MATCHFINDER_ERROR macro is provided + * if srcSize is non-zero. The ZSTD_SEQUENCE_PRODUCER_ERROR macro is provided * for convenience, but any value greater than outSeqsCapacity will be treated as * an error code. * @@ -2859,68 +2869,71 @@ ZSTDLIB_STATIC_API size_t ZSTD_insertBlock (ZSTD_DCtx* dctx, const void* bloc * written to outSeqs must be a valid parse of the src buffer. Data corruption may * occur if the parse is not valid. A parse is defined to be valid if the * following conditions hold: - * - The sum of matchLengths and literalLengths is equal to srcSize. - * - All sequences in the parse have matchLength != 0, except for the final - * sequence. matchLength is not constrained for the final sequence. - * - All offsets respect the windowSize parameter as specified in + * - The sum of matchLengths and literalLengths must equal srcSize. + * - All sequences in the parse, except for the final sequence, must have + * matchLength >= ZSTD_MINMATCH_MIN. The final sequence must have + * matchLength >= ZSTD_MINMATCH_MIN or matchLength == 0. + * - All offsets must respect the windowSize parameter as specified in * doc/zstd_compression_format.md. + * - If the final sequence has matchLength == 0, it must also have offset == 0. * * zstd will only validate these conditions (and fail compression if they do not * hold) if the ZSTD_c_validateSequences cParam is enabled. Note that sequence * validation has a performance cost. * * If the user-provided function returns an error, zstd will either fall back - * to an internal matchfinder or fail the compression operation. The user can - * choose between the two behaviors by setting the - * ZSTD_c_enableMatchFinderFallback cParam. Fallback compression will follow any - * other cParam settings, such as compression level, the same as in a normal - * compression operation. - * - * The user shall instruct zstd to use a particular ZSTD_externalMatchFinder_F - * function by calling ZSTD_registerExternalMatchFinder(cctx, externalMatchState, - * externalMatchFinder). This setting will persist until the next parameter reset - * of the CCtx. - * - * The externalMatchState must be initialized by the user before calling - * ZSTD_registerExternalMatchFinder. The user is responsible for destroying the - * externalMatchState. + * to an internal sequence producer or fail the compression operation. The user can + * choose between the two behaviors by setting the ZSTD_c_enableSeqProducerFallback + * cParam. Fallback compression will follow any other cParam settings, such as + * compression level, the same as in a normal compression operation. + * + * The user shall instruct zstd to use a particular ZSTD_sequenceProducer_F + * function by calling + * ZSTD_registerSequenceProducer(cctx, + * sequenceProducerState, + * sequenceProducer) + * This setting will persist until the next parameter reset of the CCtx. + * + * The sequenceProducerState must be initialized by the user before calling + * ZSTD_registerSequenceProducer(). The user is responsible for destroying the + * sequenceProducerState. * * *** LIMITATIONS *** - * External matchfinders are compatible with all zstd compression APIs which respect - * advanced parameters. However, there are three limitations: - * - * First, the ZSTD_c_enableLongDistanceMatching cParam is not supported. - * COMPRESSION WILL FAIL if it is enabled and the user tries to compress with an - * external matchfinder. - * - Note that ZSTD_c_enableLongDistanceMatching is auto-enabled by default in - * some cases (see its documentation for details). Users must explicitly set - * ZSTD_c_enableLongDistanceMatching to ZSTD_ps_disable in such cases if an - * external matchfinder is registered. + * This API is compatible with all zstd compression APIs which respect advanced parameters. + * However, there are three limitations: + * + * First, the ZSTD_c_enableLongDistanceMatching cParam is not currently supported. + * COMPRESSION WILL FAIL if it is enabled and the user tries to compress with a block-level + * external sequence producer. + * - Note that ZSTD_c_enableLongDistanceMatching is auto-enabled by default in some + * cases (see its documentation for details). Users must explicitly set + * ZSTD_c_enableLongDistanceMatching to ZSTD_ps_disable in such cases if an external + * sequence producer is registered. * - As of this writing, ZSTD_c_enableLongDistanceMatching is disabled by default * whenever ZSTD_c_windowLog < 128MB, but that's subject to change. Users should - * check the docs on ZSTD_c_enableLongDistanceMatching whenever the external - * matchfinder API is used in conjunction with advanced settings (like windowLog). + * check the docs on ZSTD_c_enableLongDistanceMatching whenever the Block-Level Sequence + * Producer API is used in conjunction with advanced settings (like ZSTD_c_windowLog). * - * Second, history buffers are not supported. Concretely, zstd will always pass - * dictSize == 0 to the external matchfinder (for now). This has two implications: - * - Dictionaries are not supported. Compression will *not* fail if the user + * Second, history buffers are not currently supported. Concretely, zstd will always pass + * dictSize == 0 to the external sequence producer (for now). This has two implications: + * - Dictionaries are not currently supported. Compression will *not* fail if the user * references a dictionary, but the dictionary won't have any effect. - * - Stream history is not supported. All compression APIs, including streaming - * APIs, work with the external matchfinder, but the external matchfinder won't - * receive any history from the previous block. Each block is an independent chunk. + * - Stream history is not currently supported. All advanced compression APIs, including + * streaming APIs, work with external sequence producers, but each block is treated as + * an independent chunk without history from previous blocks. * - * Third, multi-threading within a single compression is not supported. In other words, - * COMPRESSION WILL FAIL if ZSTD_c_nbWorkers > 0 and an external matchfinder is registered. + * Third, multi-threading within a single compression is not currently supported. In other words, + * COMPRESSION WILL FAIL if ZSTD_c_nbWorkers > 0 and an external sequence producer is registered. * Multi-threading across compressions is fine: simply create one CCtx per thread. * * Long-term, we plan to overcome all three limitations. There is no technical blocker to * overcoming them. It is purely a question of engineering effort. */ -#define ZSTD_EXTERNAL_MATCHFINDER_ERROR ((size_t)(-1)) +#define ZSTD_SEQUENCE_PRODUCER_ERROR ((size_t)(-1)) -typedef size_t ZSTD_externalMatchFinder_F ( - void* externalMatchState, +typedef size_t ZSTD_sequenceProducer_F ( + void* sequenceProducerState, ZSTD_Sequence* outSeqs, size_t outSeqsCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, @@ -2928,32 +2941,30 @@ typedef size_t ZSTD_externalMatchFinder_F ( size_t windowSize ); -/*! ZSTD_registerExternalMatchFinder() : - * Instruct zstd to use an external matchfinder function. +/*! ZSTD_registerSequenceProducer() : + * Instruct zstd to use a block-level external sequence producer function. * - * The externalMatchState must be initialized by the caller, and the caller is + * The sequenceProducerState must be initialized by the caller, and the caller is * responsible for managing its lifetime. This parameter is sticky across * compressions. It will remain set until the user explicitly resets compression * parameters. * - * External matchfinder registration is considered to be an "advanced parameter", - * part of the "advanced API". This means it will only have an effect on - * compression APIs which respect advanced parameters, such as compress2() and - * compressStream(). Older compression APIs such as compressCCtx(), which predate - * the introduction of "advanced parameters", will ignore any external matchfinder - * setting. + * Sequence producer registration is considered to be an "advanced parameter", + * part of the "advanced API". This means it will only have an effect on compression + * APIs which respect advanced parameters, such as compress2() and compressStream2(). + * Older compression APIs such as compressCCtx(), which predate the introduction of + * "advanced parameters", will ignore any external sequence producer setting. * - * The external matchfinder can be "cleared" by registering a NULL external - * matchfinder function pointer. This removes all limitations described above in - * the "LIMITATIONS" section of the API docs. + * The sequence producer can be "cleared" by registering a NULL function pointer. This + * removes all limitations described above in the "LIMITATIONS" section of the API docs. * - * The user is strongly encouraged to read the full API documentation (above) - * before calling this function. */ + * The user is strongly encouraged to read the full API documentation (above) before + * calling this function. */ ZSTDLIB_STATIC_API void -ZSTD_registerExternalMatchFinder( +ZSTD_registerSequenceProducer( ZSTD_CCtx* cctx, - void* externalMatchState, - ZSTD_externalMatchFinder_F* externalMatchFinder + void* sequenceProducerState, + ZSTD_sequenceProducer_F* sequenceProducer ); #endif /* ZSTD_H_ZSTD_STATIC_LINKING_ONLY */ diff --git a/libfenrir/src/main/jni/compress/zstd/zstd_errors.h b/libfenrir/src/main/jni/compress/zstd/zstd_errors.h index 6a66bedcb..dc75eeeba 100644 --- a/libfenrir/src/main/jni/compress/zstd/zstd_errors.h +++ b/libfenrir/src/main/jni/compress/zstd/zstd_errors.h @@ -95,7 +95,7 @@ typedef enum { ZSTD_error_seekableIO = 102, ZSTD_error_dstBuffer_wrong = 104, ZSTD_error_srcBuffer_wrong = 105, - ZSTD_error_externalMatchFinder_failed = 106, + ZSTD_error_sequenceProducer_failed = 106, ZSTD_error_externalSequences_invalid = 107, ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ } ZSTD_ErrorCode; diff --git a/material/build.gradle b/material/build.gradle index 2338ed989..0ee81b34b 100644 --- a/material/build.gradle +++ b/material/build.gradle @@ -3,7 +3,7 @@ plugins { id("kotlin-android") } -//1.9.0-alpha01 +//1.9.0-alpha02 def srcDirs = [ 'com/google/android/material/animation', diff --git a/material/java/com/google/android/material/appbar/res-public/values/public.xml b/material/java/com/google/android/material/appbar/res-public/values/public.xml index 1b357e185..b350134b0 100644 --- a/material/java/com/google/android/material/appbar/res-public/values/public.xml +++ b/material/java/com/google/android/material/appbar/res-public/values/public.xml @@ -23,6 +23,7 @@ + diff --git a/material/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java b/material/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java index 021db832a..236012d93 100644 --- a/material/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java +++ b/material/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java @@ -531,6 +531,7 @@ public boolean onLayoutChild( peekHeightMin = parent.getResources().getDimensionPixelSize(R.dimen.design_bottom_sheet_peek_height_min); setWindowInsetsListener(child); + ViewCompat.setWindowInsetsAnimationCallback(child, new InsetsAnimationCallback(child)); viewRef = new WeakReference<>(child); // Only set MaterialShapeDrawable as background if shapeTheming is enabled, otherwise will // default to android:background declared in styles or layout. diff --git a/material/java/com/google/android/material/bottomsheet/InsetsAnimationCallback.java b/material/java/com/google/android/material/bottomsheet/InsetsAnimationCallback.java new file mode 100644 index 000000000..e9d717344 --- /dev/null +++ b/material/java/com/google/android/material/bottomsheet/InsetsAnimationCallback.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.material.bottomsheet; + +import android.view.View; +import androidx.annotation.NonNull; +import androidx.core.view.WindowInsetsAnimationCompat; +import androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat; +import androidx.core.view.WindowInsetsCompat; +import com.google.android.material.animation.AnimationUtils; +import java.util.List; + +class InsetsAnimationCallback extends WindowInsetsAnimationCompat.Callback { + + private final View view; + + private int startY; + private int startTranslationY; + + private final int[] tmpLocation = new int[2]; + + public InsetsAnimationCallback(View view) { + super(DISPATCH_MODE_STOP); + this.view = view; + } + + @Override + public void onPrepare(@NonNull WindowInsetsAnimationCompat windowInsetsAnimationCompat) { + view.getLocationOnScreen(tmpLocation); + startY = tmpLocation[1]; + } + + @NonNull + @Override + public BoundsCompat onStart( + @NonNull WindowInsetsAnimationCompat windowInsetsAnimationCompat, + @NonNull BoundsCompat boundsCompat) { + view.getLocationOnScreen(tmpLocation); + int endY = tmpLocation[1]; + startTranslationY = startY - endY; + + // Move the view back to its original position before the insets were applied. + view.setTranslationY(startTranslationY); + + return boundsCompat; + } + + @NonNull + @Override + public WindowInsetsCompat onProgress( + @NonNull WindowInsetsCompat insets, + @NonNull List animationList) { + for (WindowInsetsAnimationCompat animation : animationList) { + if ((animation.getTypeMask() & WindowInsetsCompat.Type.ime()) != 0) { + // Move the view to match the animated position of the keyboard. + float translationY = + AnimationUtils.lerp(startTranslationY, 0, animation.getInterpolatedFraction()); + view.setTranslationY(translationY); + break; + } + } + return insets; + } + + @Override + public void onEnd(@NonNull WindowInsetsAnimationCompat windowInsetsAnimationCompat) { + view.setTranslationY(0f); + } +} diff --git a/material/java/com/google/android/material/bottomsheet/res/values/themes_base.xml b/material/java/com/google/android/material/bottomsheet/res/values/themes_base.xml index 2f96d701c..2f9768814 100644 --- a/material/java/com/google/android/material/bottomsheet/res/values/themes_base.xml +++ b/material/java/com/google/android/material/bottomsheet/res/values/themes_base.xml @@ -17,6 +17,7 @@ + + + diff --git a/material/java/com/google/android/material/chip/res/values/styles.xml b/material/java/com/google/android/material/chip/res/values/styles.xml index de3d4faae..71fdec641 100644 --- a/material/java/com/google/android/material/chip/res/values/styles.xml +++ b/material/java/com/google/android/material/chip/res/values/styles.xml @@ -388,11 +388,11 @@ diff --git a/material/java/com/google/android/material/color/ColorResourcesOverride.java b/material/java/com/google/android/material/color/ColorResourcesOverride.java index 8b36a989d..6aa7b7fdd 100644 --- a/material/java/com/google/android/material/color/ColorResourcesOverride.java +++ b/material/java/com/google/android/material/color/ColorResourcesOverride.java @@ -47,6 +47,18 @@ public interface ColorResourcesOverride { boolean applyIfPossible( @NonNull Context context, @NonNull Map colorResourceIdsToColorValues); + /** + * Wraps the given Context with the theme overlay where color resources are updated at runtime. + * If not possible, the original Context will be returned. + * + * @param context The target context. + * @param colorResourceIdsToColorValues The mapping from the color resources id to the updated + * color value. + */ + @NonNull + Context wrapContextIfPossible( + @NonNull Context context, @NonNull Map colorResourceIdsToColorValues); + @Nullable static ColorResourcesOverride getInstance() { if (VERSION_CODES.R <= VERSION.SDK_INT && VERSION.SDK_INT <= VERSION_CODES.TIRAMISU) { diff --git a/material/java/com/google/android/material/color/ResourcesLoaderColorResourcesOverride.java b/material/java/com/google/android/material/color/ResourcesLoaderColorResourcesOverride.java index 58f2fee40..cae7deee0 100644 --- a/material/java/com/google/android/material/color/ResourcesLoaderColorResourcesOverride.java +++ b/material/java/com/google/android/material/color/ResourcesLoaderColorResourcesOverride.java @@ -19,7 +19,10 @@ import com.google.android.material.R; import android.content.Context; +import android.content.res.Configuration; import android.os.Build.VERSION_CODES; +import android.view.ContextThemeWrapper; +import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import java.util.Map; @@ -50,6 +53,30 @@ public boolean applyIfPossible( return false; } + /** + * Wraps the given Context with the theme overlay where color resources are updated at runtime. + * If not possible, the original Context will be returned. + * + * @param context The target context. + * @param colorResourceIdsToColorValues The mapping from the color resources id to the updated + * color value. + */ + @Override + @NonNull + public Context wrapContextIfPossible( + Context context, Map colorResourceIdsToColorValues) { + ContextThemeWrapper themeWrapper = + new ContextThemeWrapper(context, R.style.ThemeOverlay_Material3_PersonalizedColors); + // Because ContextThemeWrapper does not provide a new set of resources, override config to + // retrieve the new set of resources and to keep the original context's resources intact. + themeWrapper.applyOverrideConfiguration(new Configuration()); + + return ResourcesLoaderUtils.addResourcesLoaderToContext( + themeWrapper, colorResourceIdsToColorValues) + ? themeWrapper + : context; + } + static ColorResourcesOverride getInstance() { return ResourcesLoaderColorResourcesOverrideSingleton.INSTANCE; } diff --git a/material/java/com/google/android/material/color/ThemeUtils.java b/material/java/com/google/android/material/color/ThemeUtils.java index f0073f4fb..10be154bf 100644 --- a/material/java/com/google/android/material/color/ThemeUtils.java +++ b/material/java/com/google/android/material/color/ThemeUtils.java @@ -16,6 +16,8 @@ package com.google.android.material.color; +import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; + import android.app.Activity; import android.content.Context; import android.content.res.Resources.Theme; @@ -23,14 +25,22 @@ import android.view.Window; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; import androidx.annotation.StyleRes; -/** Utility methods for theme. */ -final class ThemeUtils { +// TODO(b/269781013): move this class to internal folder, which involves resolving cyclic dependency +// between color and internal folders +/** + * Utility methods for theme. + * + * @hide + */ +@RestrictTo(LIBRARY_GROUP) +public final class ThemeUtils { private ThemeUtils() {} - static void applyThemeOverlay(@NonNull Context context, @StyleRes int theme) { + public static void applyThemeOverlay(@NonNull Context context, @StyleRes int theme) { // Use applyStyle() instead of setTheme() due to Force Dark issue. context.getTheme().applyStyle(theme, /* force= */ true); diff --git a/material/java/com/google/android/material/datepicker/DateSelector.java b/material/java/com/google/android/material/datepicker/DateSelector.java index 5f473b1fa..649211130 100644 --- a/material/java/com/google/android/material/datepicker/DateSelector.java +++ b/material/java/com/google/android/material/datepicker/DateSelector.java @@ -146,6 +146,12 @@ static void showKeyboardWithAutoHideBehavior(@NonNull EditText... editTexts) { editText.setOnFocusChangeListener(listener); } - ViewUtils.requestFocusAndShowKeyboard(editTexts[0]); + // TODO(b/246354286): Investigate issue with keyboard not showing on Android 12+ + View viewToFocus = editTexts[0]; + viewToFocus.postDelayed( + () -> + ViewUtils.requestFocusAndShowKeyboard( + viewToFocus, /* useWindowInsetsController= */ false), + 100); } } diff --git a/material/java/com/google/android/material/internal/ViewUtils.java b/material/java/com/google/android/material/internal/ViewUtils.java index cc1152684..70bc3db65 100644 --- a/material/java/com/google/android/material/internal/ViewUtils.java +++ b/material/java/com/google/android/material/internal/ViewUtils.java @@ -80,6 +80,16 @@ public static void showKeyboard(@NonNull View view, boolean useWindowInsetsContr getInputMethodManager(view).showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); } + public static void requestFocusAndShowKeyboard(@NonNull final View view) { + requestFocusAndShowKeyboard(view, /* useWindowInsetsController= */ true); + } + + public static void requestFocusAndShowKeyboard( + @NonNull final View view, boolean useWindowInsetsController) { + view.requestFocus(); + view.post(() -> showKeyboard(view, useWindowInsetsController)); + } + public static void hideKeyboard(@NonNull View view) { hideKeyboard(view, /* useWindowInsetsController= */ true); } @@ -161,20 +171,6 @@ public static float dpToPx(@NonNull Context context, @Dimension(unit = Dimension return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()); } - public static void requestFocusAndShowKeyboard(@NonNull final View view) { - view.requestFocus(); - view.post( - new Runnable() { - @Override - public void run() { - InputMethodManager inputMethodManager = - (InputMethodManager) - view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - inputMethodManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); - } - }); - } - /** * Wrapper around {@link androidx.core.view.OnApplyWindowInsetsListener} which also passes the * initial padding set on the view. Used with {@link #doOnApplyWindowInsets(View, diff --git a/material/java/com/google/android/material/internal/WindowUtils.java b/material/java/com/google/android/material/internal/WindowUtils.java new file mode 100644 index 000000000..fe49868c8 --- /dev/null +++ b/material/java/com/google/android/material/internal/WindowUtils.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.material.internal; + +import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; + +import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.Build; +import android.util.Log; +import android.view.Display; +import android.view.WindowManager; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.annotation.RestrictTo; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * A util class for window operations. + * + * @hide + */ +@RestrictTo(LIBRARY_GROUP) +public class WindowUtils { + + private static final String TAG = WindowUtils.class.getSimpleName(); + + private WindowUtils() {} + + @NonNull + public static Rect getCurrentWindowBounds(@NonNull Context context) { + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + return Api30Impl.getCurrentWindowBounds(windowManager); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + return Api17Impl.getCurrentWindowBounds(windowManager); + } else { + return Api14Impl.getCurrentWindowBounds(windowManager); + } + } + + @RequiresApi(api = Build.VERSION_CODES.R) + private static class Api30Impl { + + @NonNull + static Rect getCurrentWindowBounds(@NonNull WindowManager windowManager) { + return windowManager.getCurrentWindowMetrics().getBounds(); + } + } + + @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) + private static class Api17Impl { + + @NonNull + static Rect getCurrentWindowBounds(@NonNull WindowManager windowManager) { + Display defaultDisplay = windowManager.getDefaultDisplay(); + + Point defaultDisplaySize = new Point(); + defaultDisplay.getRealSize(defaultDisplaySize); + + Rect bounds = new Rect(); + bounds.right = defaultDisplaySize.x; + bounds.bottom = defaultDisplaySize.y; + + return bounds; + } + } + + private static class Api14Impl { + + @NonNull + static Rect getCurrentWindowBounds(@NonNull WindowManager windowManager) { + Display defaultDisplay = windowManager.getDefaultDisplay(); + Point defaultDisplaySize = getRealSizeForDisplay(defaultDisplay); + + Rect bounds = new Rect(); + if (defaultDisplaySize.x == 0 || defaultDisplaySize.y == 0) { + defaultDisplay.getRectSize(bounds); + } else { + bounds.right = defaultDisplaySize.x; + bounds.bottom = defaultDisplaySize.y; + } + + return bounds; + } + + private static Point getRealSizeForDisplay(Display display) { + Point size = new Point(); + try { + Method getRealSizeMethod = Display.class.getDeclaredMethod("getRealSize", Point.class); + getRealSizeMethod.setAccessible(true); + getRealSizeMethod.invoke(display, size); + } catch (NoSuchMethodException e) { + Log.w(TAG, e); + } catch (IllegalAccessException e) { + Log.w(TAG, e); + } catch (InvocationTargetException e) { + Log.w(TAG, e); + } + return size; + } + } +} diff --git a/material/java/com/google/android/material/navigation/NavigationView.java b/material/java/com/google/android/material/navigation/NavigationView.java index c200df38c..87f448983 100644 --- a/material/java/com/google/android/material/navigation/NavigationView.java +++ b/material/java/com/google/android/material/navigation/NavigationView.java @@ -27,6 +27,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Path; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -44,7 +45,6 @@ import androidx.appcompat.view.menu.MenuItemImpl; import androidx.appcompat.widget.TintTypedArray; import android.util.AttributeSet; -import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.Gravity; import android.view.Menu; @@ -73,6 +73,7 @@ import com.google.android.material.internal.NavigationMenuPresenter; import com.google.android.material.internal.ScrimInsetsFrameLayout; import com.google.android.material.internal.ThemeEnforcement; +import com.google.android.material.internal.WindowUtils; import com.google.android.material.resources.MaterialResources; import com.google.android.material.ripple.RippleUtils; import com.google.android.material.shape.MaterialShapeDrawable; @@ -975,11 +976,10 @@ public void onGlobalLayout() { Activity activity = ContextUtils.getActivity(getContext()); if (activity != null && VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - DisplayMetrics displayMetrics = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics); + Rect displayBounds = WindowUtils.getCurrentWindowBounds(activity); boolean isBehindSystemNav = - displayMetrics.heightPixels - getHeight() == tmpLocation[1]; + displayBounds.height() - getHeight() == tmpLocation[1]; boolean hasNonZeroAlpha = Color.alpha(activity.getWindow().getNavigationBarColor()) != 0; setDrawBottomInsetForeground( @@ -988,8 +988,8 @@ public void onGlobalLayout() { // The navigation view could be right aligned or just hidden out of view in a drawer // layout when the global layout listener is called. boolean isOnRightSide = - (displayMetrics.widthPixels == tmpLocation[0]) - || (displayMetrics.widthPixels - getWidth() == tmpLocation[0]); + (displayBounds.width() == tmpLocation[0]) + || (displayBounds.width() - getWidth() == tmpLocation[0]); setDrawRightInsetForeground(isOnRightSide); } diff --git a/material/java/com/google/android/material/progressindicator/LinearDrawingDelegate.java b/material/java/com/google/android/material/progressindicator/LinearDrawingDelegate.java index b99693cf0..f35fab699 100644 --- a/material/java/com/google/android/material/progressindicator/LinearDrawingDelegate.java +++ b/material/java/com/google/android/material/progressindicator/LinearDrawingDelegate.java @@ -20,6 +20,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; +import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import androidx.annotation.ColorInt; @@ -34,6 +35,7 @@ final class LinearDrawingDelegate extends DrawingDelegate= extraBottomMarginGestureInset) { // No need to add extra offset if view is already outside of bottom gesture area + appliedBottomMarginGestureInset = extraBottomMarginGestureInset; return; } @@ -312,6 +313,8 @@ public void run() { return; } + appliedBottomMarginGestureInset = extraBottomMarginGestureInset; + // Move view outside of bottom gesture area MarginLayoutParams marginParams = (MarginLayoutParams) layoutParams; marginParams.bottomMargin += extraBottomMarginGestureInset - currentInsetBottom; @@ -322,9 +325,11 @@ public void run() { private int extraBottomMarginWindowInset; private int extraLeftMarginWindowInset; private int extraRightMarginWindowInset; - private int extraBottomMarginGestureInset; private int extraBottomMarginAnchorView; + private int extraBottomMarginGestureInset; + private int appliedBottomMarginGestureInset; + private boolean pendingShowingView; private List> callbacks; @@ -455,10 +460,16 @@ public boolean performAccessibilityAction(View host, int action, Bundle args) { private void updateMargins() { LayoutParams layoutParams = view.getLayoutParams(); - if (!(layoutParams instanceof MarginLayoutParams) || view.originalMargins == null) { + if (!(layoutParams instanceof MarginLayoutParams)) { Log.w(TAG, "Unable to update margins because layout params are not MarginLayoutParams"); return; } + + if (view.originalMargins == null) { + Log.w(TAG, "Unable to update margins because original view margins are not set"); + return; + } + if (view.getParent() == null) { // Parent will set layout params to view again. Wait for addView() is done to update layout // params, in case we save the already updated margins as the original margins. @@ -467,17 +478,32 @@ private void updateMargins() { int extraBottomMargin = getAnchorView() != null ? extraBottomMarginAnchorView : extraBottomMarginWindowInset; - MarginLayoutParams marginParams = (MarginLayoutParams) layoutParams; - marginParams.bottomMargin = view.originalMargins.bottom + extraBottomMargin; - marginParams.leftMargin = view.originalMargins.left + extraLeftMarginWindowInset; - marginParams.rightMargin = view.originalMargins.right + extraRightMarginWindowInset; - marginParams.topMargin = view.originalMargins.top; - view.requestLayout(); - if (VERSION.SDK_INT >= VERSION_CODES.Q && shouldUpdateGestureInset()) { - // Ensure there is only one gesture inset runnable running at a time - view.removeCallbacks(bottomMarginGestureInsetRunnable); - view.post(bottomMarginGestureInsetRunnable); + MarginLayoutParams marginParams = (MarginLayoutParams) layoutParams; + int newBottomMargin = view.originalMargins.bottom + extraBottomMargin; + int newLeftMargin = view.originalMargins.left + extraLeftMarginWindowInset; + int newRightMargin = view.originalMargins.right + extraRightMarginWindowInset; + int newTopMargin = view.originalMargins.top; + + boolean marginChanged = + marginParams.bottomMargin != newBottomMargin + || marginParams.leftMargin != newLeftMargin + || marginParams.rightMargin != newRightMargin + || marginParams.topMargin != newTopMargin; + if (marginChanged) { + marginParams.bottomMargin = newBottomMargin; + marginParams.leftMargin = newLeftMargin; + marginParams.rightMargin = newRightMargin; + marginParams.topMargin = newTopMargin; + view.requestLayout(); + } + + if (marginChanged || appliedBottomMarginGestureInset != extraBottomMarginGestureInset) { + if (VERSION.SDK_INT >= VERSION_CODES.Q && shouldUpdateGestureInset()) { + // Ensure there is only one gesture inset runnable running at a time + view.removeCallbacks(bottomMarginGestureInsetRunnable); + view.post(bottomMarginGestureInsetRunnable); + } } } @@ -823,14 +849,6 @@ private int getViewAbsoluteBottom() { return absoluteLocation[1] + view.getHeight(); } - @RequiresApi(VERSION_CODES.JELLY_BEAN_MR1) - private int getScreenHeight() { - WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - DisplayMetrics displayMetrics = new DisplayMetrics(); - windowManager.getDefaultDisplay().getRealMetrics(displayMetrics); - return displayMetrics.heightPixels; - } - private void setUpBehavior(CoordinatorLayout.LayoutParams lp) { // If our LayoutParams are from a CoordinatorLayout, we'll setup our Behavior CoordinatorLayout.LayoutParams clp = lp; @@ -878,11 +896,7 @@ public void onDragStateChanged(int state) { } private void recalculateAndUpdateMargins() { - int newBottomMarginAnchorView = calculateBottomMarginForAnchorView(); - if (newBottomMarginAnchorView == extraBottomMarginAnchorView) { - return; - } - extraBottomMarginAnchorView = newBottomMarginAnchorView; + extraBottomMarginAnchorView = calculateBottomMarginForAnchorView(); updateMargins(); } diff --git a/material/java/com/google/android/material/tabs/TabLayout.java b/material/java/com/google/android/material/tabs/TabLayout.java index 88e4b25d5..4c1508cb1 100644 --- a/material/java/com/google/android/material/tabs/TabLayout.java +++ b/material/java/com/google/android/material/tabs/TabLayout.java @@ -758,6 +758,20 @@ public void setScrollPosition( float positionOffset, boolean updateSelectedTabView, boolean updateIndicatorPosition) { + setScrollPosition( + position, + positionOffset, + updateSelectedTabView, + updateIndicatorPosition, + /* alwaysScroll= */ true); + } + + void setScrollPosition( + int position, + float positionOffset, + boolean updateSelectedTabView, + boolean updateIndicatorPosition, + boolean alwaysScroll) { final int roundedPosition = Math.round(position + positionOffset); if (roundedPosition < 0 || roundedPosition >= slidingTabIndicator.getChildCount()) { return; @@ -772,7 +786,36 @@ public void setScrollPosition( if (scrollAnimator != null && scrollAnimator.isRunning()) { scrollAnimator.cancel(); } - scrollTo(position < 0 ? 0 : calculateScrollXForTab(position, positionOffset), 0); + int scrollXForPosition = calculateScrollXForTab(position, positionOffset); + int scrollX = getScrollX(); + // If the position is smaller than the selected tab position, the position is getting larger + // to reach the selected tab position so scrollX is increasing. + // We only want to update the scroll position if the new scroll position is greater than + // the current scroll position. + // Conversely if the position is greater than the selected tab position, the position is + // getting smaller to reach the selected tab position so scrollX is decreasing. + // We only update the scroll position if the new scroll position is less than the current + // scroll position. + // Lastly if the position is equal to the selected position, we want to set the scroll + // position which also updates the selected tab view and the indicator. + boolean toMove = + (position < getSelectedTabPosition() && scrollXForPosition >= scrollX) + || (position > getSelectedTabPosition() && scrollXForPosition <= scrollX) + || (position == getSelectedTabPosition()); + // If the layout direction is RTL, the scrollXForPosition and scrollX comparisons are + // reversed since scrollX values remain the same in RTL but tab positions go RTL. + if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) { + toMove = + (position < getSelectedTabPosition() && scrollXForPosition <= scrollX) + || (position > getSelectedTabPosition() + && scrollXForPosition >= scrollX) + || (position == getSelectedTabPosition()); + } + // We want to scroll if alwaysScroll is true, the viewpager is being dragged, or if we should + // scroll by the rules above. + if (toMove || viewPagerScrollState == SCROLL_STATE_DRAGGING || alwaysScroll) { + scrollTo(position < 0 ? 0 : scrollXForPosition, 0); + } // Update the 'selected state' view as we scroll, if enabled if (updateSelectedTabView) { @@ -3537,7 +3580,7 @@ public void onPageScrolled( final boolean updateIndicator = !(scrollState == SCROLL_STATE_SETTLING && previousScrollState == SCROLL_STATE_IDLE); tabLayout.setScrollPosition( - position, positionOffset, updateSelectedTabView, updateIndicator); + position, positionOffset, updateSelectedTabView, updateIndicator, false); } } diff --git a/material/java/com/google/android/material/tabs/TabLayoutMediator.java b/material/java/com/google/android/material/tabs/TabLayoutMediator.java index 94e219ae0..38a9a08e2 100644 --- a/material/java/com/google/android/material/tabs/TabLayoutMediator.java +++ b/material/java/com/google/android/material/tabs/TabLayoutMediator.java @@ -230,7 +230,7 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse boolean updateIndicator = !(scrollState == SCROLL_STATE_SETTLING && previousScrollState == SCROLL_STATE_IDLE); tabLayout.setScrollPosition( - position, positionOffset, updateSelectedTabView, updateIndicator); + position, positionOffset, updateSelectedTabView, updateIndicator, false); } } diff --git a/material/java/com/google/android/material/textfield/CutoutDrawable.java b/material/java/com/google/android/material/textfield/CutoutDrawable.java index 15dda0f19..6d8130fc6 100644 --- a/material/java/com/google/android/material/textfield/CutoutDrawable.java +++ b/material/java/com/google/android/material/textfield/CutoutDrawable.java @@ -25,6 +25,7 @@ import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.Region.Op; +import android.graphics.drawable.Drawable; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.view.View; @@ -38,31 +39,44 @@ * outline mode. */ class CutoutDrawable extends MaterialShapeDrawable { - @NonNull protected final RectF cutoutBounds; + @NonNull CutoutDrawableState drawableState; static CutoutDrawable create(@Nullable ShapeAppearanceModel shapeAppearanceModel) { + return create(new CutoutDrawableState( + shapeAppearanceModel != null ? shapeAppearanceModel : new ShapeAppearanceModel(), + new RectF())); + } + + private static CutoutDrawable create(@NonNull CutoutDrawableState drawableState) { return VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2 - ? new ImplApi18(shapeAppearanceModel) - : new ImplApi14(shapeAppearanceModel); + ? new ImplApi18(drawableState) + : new ImplApi14(drawableState); + } + + private CutoutDrawable(@NonNull CutoutDrawableState drawableState) { + super(drawableState); + this.drawableState = drawableState; } - private CutoutDrawable(@Nullable ShapeAppearanceModel shapeAppearanceModel) { - super(shapeAppearanceModel != null ? shapeAppearanceModel : new ShapeAppearanceModel()); - cutoutBounds = new RectF(); + @NonNull + @Override + public Drawable mutate() { + drawableState = new CutoutDrawableState(drawableState); + return this; } boolean hasCutout() { - return !cutoutBounds.isEmpty(); + return !drawableState.cutoutBounds.isEmpty(); } void setCutout(float left, float top, float right, float bottom) { // Avoid expensive redraws by only calling invalidateSelf if one of the cutout's dimensions has // changed. - if (left != cutoutBounds.left - || top != cutoutBounds.top - || right != cutoutBounds.right - || bottom != cutoutBounds.bottom) { - cutoutBounds.set(left, top, right, bottom); + if (left != drawableState.cutoutBounds.left + || top != drawableState.cutoutBounds.top + || right != drawableState.cutoutBounds.right + || bottom != drawableState.cutoutBounds.bottom) { + drawableState.cutoutBounds.set(left, top, right, bottom); invalidateSelf(); } } @@ -78,21 +92,21 @@ void removeCutout() { @TargetApi(VERSION_CODES.JELLY_BEAN_MR2) private static class ImplApi18 extends CutoutDrawable { - ImplApi18(@Nullable ShapeAppearanceModel shapeAppearanceModel) { - super(shapeAppearanceModel); + ImplApi18(@NonNull CutoutDrawableState drawableState) { + super(drawableState); } @Override protected void drawStrokeShape(@NonNull Canvas canvas) { - if (cutoutBounds.isEmpty()) { + if (drawableState.cutoutBounds.isEmpty()) { super.drawStrokeShape(canvas); } else { // Saves the canvas so we can restore the clip after drawing the stroke. canvas.save(); if (VERSION.SDK_INT >= VERSION_CODES.O) { - canvas.clipOutRect(cutoutBounds); + canvas.clipOutRect(drawableState.cutoutBounds); } else { - canvas.clipRect(cutoutBounds, Op.DIFFERENCE); + canvas.clipRect(drawableState.cutoutBounds, Op.DIFFERENCE); } super.drawStrokeShape(canvas); canvas.restore(); @@ -106,8 +120,8 @@ private static class ImplApi14 extends CutoutDrawable { private Paint cutoutPaint; private int savedLayer; - ImplApi14(@Nullable ShapeAppearanceModel shapeAppearanceModel) { - super(shapeAppearanceModel); + ImplApi14(@NonNull CutoutDrawableState drawableState) { + super(drawableState); } @Override @@ -120,7 +134,7 @@ public void draw(@NonNull Canvas canvas) { @Override protected void drawStrokeShape(@NonNull Canvas canvas) { super.drawStrokeShape(canvas); - canvas.drawRect(cutoutBounds, getCutoutPaint()); + canvas.drawRect(drawableState.cutoutBounds, getCutoutPaint()); } private Paint getCutoutPaint() { @@ -168,4 +182,28 @@ private boolean useHardwareLayer(Callback callback) { return callback instanceof View; } } + + private static final class CutoutDrawableState extends MaterialShapeDrawableState { + @NonNull private final RectF cutoutBounds; + + private CutoutDrawableState( + @NonNull ShapeAppearanceModel shapeAppearanceModel, @NonNull RectF cutoutBounds) { + super(shapeAppearanceModel, null); + this.cutoutBounds = cutoutBounds; + } + + private CutoutDrawableState(@NonNull CutoutDrawableState state) { + super(state); + this.cutoutBounds = state.cutoutBounds; + } + + @NonNull + @Override + public Drawable newDrawable() { + CutoutDrawable drawable = CutoutDrawable.create(this); + // Force the calculation of the path for the new drawable. + drawable.invalidateSelf(); + return drawable; + } + } } diff --git a/material/java/com/google/android/material/textfield/EndCompoundLayout.java b/material/java/com/google/android/material/textfield/EndCompoundLayout.java index fb119d70c..7465f87e3 100644 --- a/material/java/com/google/android/material/textfield/EndCompoundLayout.java +++ b/material/java/com/google/android/material/textfield/EndCompoundLayout.java @@ -737,6 +737,21 @@ void updateSuffixTextViewPadding() { textInputLayout.editText.getPaddingBottom()); } + int getSuffixTextEndOffset() { + int endIconOffset; + if (isEndIconVisible() || isErrorIconVisible()) { + endIconOffset = + endIconView.getMeasuredWidth() + + MarginLayoutParamsCompat.getMarginStart( + (MarginLayoutParams) endIconView.getLayoutParams()); + } else { + endIconOffset = 0; + } + return ViewCompat.getPaddingEnd(this) + + ViewCompat.getPaddingEnd(suffixTextView) + + endIconOffset; + } + @Nullable CheckableImageButton getCurrentEndIconView() { if (isErrorIconVisible()) { diff --git a/material/java/com/google/android/material/textfield/StartCompoundLayout.java b/material/java/com/google/android/material/textfield/StartCompoundLayout.java index ebf845551..61f0df192 100644 --- a/material/java/com/google/android/material/textfield/StartCompoundLayout.java +++ b/material/java/com/google/android/material/textfield/StartCompoundLayout.java @@ -328,6 +328,21 @@ void updatePrefixTextViewPadding() { editText.getCompoundPaddingBottom()); } + int getPrefixTextStartOffset() { + int startIconOffset; + if (isStartIconVisible()) { + startIconOffset = + startIconView.getMeasuredWidth() + + MarginLayoutParamsCompat.getMarginEnd( + (MarginLayoutParams) startIconView.getLayoutParams()); + } else { + startIconOffset = 0; + } + return ViewCompat.getPaddingStart(this) + + ViewCompat.getPaddingStart(prefixTextView) + + startIconOffset; + } + void onHintStateChanged(boolean hintExpanded) { this.hintExpanded = hintExpanded; updateVisibility(); diff --git a/material/java/com/google/android/material/textfield/TextInputLayout.java b/material/java/com/google/android/material/textfield/TextInputLayout.java index f1032ad26..acda4ac93 100644 --- a/material/java/com/google/android/material/textfield/TextInputLayout.java +++ b/material/java/com/google/android/material/textfield/TextInputLayout.java @@ -2769,35 +2769,37 @@ private Rect calculateCollapsedTextBounds(@NonNull Rect rect) { bounds.right = rect.right - editText.getPaddingRight(); return bounds; case BOX_BACKGROUND_FILLED: - bounds.left = getLabelLeftBoundAlightWithPrefix(rect.left, isRtl); + bounds.left = getLabelLeftBoundAlignedWithPrefixAndSuffix(rect.left, isRtl); bounds.top = rect.top + boxCollapsedPaddingTopPx; - bounds.right = getLabelRightBoundAlignedWithSuffix(rect.right, isRtl); + bounds.right = getLabelRightBoundAlignedWithPrefixAndSuffix(rect.right, isRtl); return bounds; case BOX_BACKGROUND_NONE: default: - bounds.left = getLabelLeftBoundAlightWithPrefix(rect.left, isRtl); + bounds.left = getLabelLeftBoundAlignedWithPrefixAndSuffix(rect.left, isRtl); bounds.top = getPaddingTop(); - bounds.right = getLabelRightBoundAlignedWithSuffix(rect.right, isRtl); + bounds.right = getLabelRightBoundAlignedWithPrefixAndSuffix(rect.right, isRtl); return bounds; } } - private int getLabelLeftBoundAlightWithPrefix(int rectLeft, boolean isRtl) { - int left = rectLeft + editText.getCompoundPaddingLeft(); - if (getPrefixText() != null && !isRtl) { - // Label should be vertically aligned with prefix - left = left - getPrefixTextView().getMeasuredWidth() + getPrefixTextView().getPaddingLeft(); + private int getLabelLeftBoundAlignedWithPrefixAndSuffix(int rectLeft, boolean isRtl) { + if (!isRtl && getPrefixText() != null) { + return rectLeft + startLayout.getPrefixTextStartOffset(); } - return left; + if (isRtl && getSuffixText() != null) { + return rectLeft + endLayout.getSuffixTextEndOffset(); + } + return rectLeft + editText.getCompoundPaddingLeft(); } - private int getLabelRightBoundAlignedWithSuffix(int rectRight, boolean isRtl) { - int right = rectRight - editText.getCompoundPaddingRight(); - if (getPrefixText() != null && isRtl) { - // Label should be vertically aligned with prefix if in RTL - right += getPrefixTextView().getMeasuredWidth() - getPrefixTextView().getPaddingRight(); + private int getLabelRightBoundAlignedWithPrefixAndSuffix(int rectRight, boolean isRtl) { + if (!isRtl && getSuffixText() != null) { + return rectRight - endLayout.getSuffixTextEndOffset(); + } + if (isRtl && getPrefixText() != null) { + return rectRight - startLayout.getPrefixTextStartOffset(); } - return right; + return rectRight - editText.getCompoundPaddingRight(); } @NonNull diff --git a/material/java/com/google/android/material/timepicker/ChipTextInputComboView.java b/material/java/com/google/android/material/timepicker/ChipTextInputComboView.java index b3add4ae3..883cf3e4e 100644 --- a/material/java/com/google/android/material/timepicker/ChipTextInputComboView.java +++ b/material/java/com/google/android/material/timepicker/ChipTextInputComboView.java @@ -108,7 +108,7 @@ public void setChecked(boolean checked) { // Instead, the text in chip should be hidden. chip.setVisibility(checked ? GONE : VISIBLE); if (isChecked()) { - ViewUtils.requestFocusAndShowKeyboard(editText); + ViewUtils.requestFocusAndShowKeyboard(editText, /* useWindowInsetsController= */ false); } } diff --git a/preference/src/main/kotlin/de/maxr1998/modernpreferences/helpers/PreferencesDsl.kt b/preference/src/main/kotlin/de/maxr1998/modernpreferences/helpers/PreferencesDsl.kt index 6ecd133a8..d27ec1668 100644 --- a/preference/src/main/kotlin/de/maxr1998/modernpreferences/helpers/PreferencesDsl.kt +++ b/preference/src/main/kotlin/de/maxr1998/modernpreferences/helpers/PreferencesDsl.kt @@ -351,4 +351,18 @@ inline fun ColorPickPreference.onColorBeforeChange(crossinline callback: (Int) - ColorPickPreference.OnColorBeforeChangeListener { _, selection -> callback(selection) } +} + +inline fun SeekBarPreference.onSeek(crossinline callback: (Int) -> Unit) { + seekAfterListener = + SeekBarPreference.OnSeekAfterListener { _, selection -> + callback(selection) + } +} + +inline fun SeekBarPreference.onSeekBefore(crossinline callback: (Int) -> Boolean) { + seekBeforeListener = + SeekBarPreference.OnSeekBeforeListener { _, selection -> + callback(selection) + } } \ No newline at end of file diff --git a/preference/src/main/kotlin/de/maxr1998/modernpreferences/preferences/SeekBarPreference.kt b/preference/src/main/kotlin/de/maxr1998/modernpreferences/preferences/SeekBarPreference.kt index a1586124d..76835aed5 100644 --- a/preference/src/main/kotlin/de/maxr1998/modernpreferences/preferences/SeekBarPreference.kt +++ b/preference/src/main/kotlin/de/maxr1998/modernpreferences/preferences/SeekBarPreference.kt @@ -47,14 +47,16 @@ class SeekBarPreference(key: String) : Preference(key) { var value: Int get() = valueInternal set(v) { - if (v != valueInternal && seekListener?.onSeek(this, null, v) != false) { + if (v != valueInternal && seekBeforeListener?.onSeekBefore(this, v) != false) { valueInternal = v commitInt(value) requestRebind() + seekAfterListener?.onSeekAfter(this, v) } } - var seekListener: OnSeekListener? = null + var seekBeforeListener: OnSeekBeforeListener? = null + var seekAfterListener: OnSeekAfterListener? = null var formatter: (Int) -> String = Int::toString fun copySeek(o: SeekBarPreference): SeekBarPreference { @@ -63,7 +65,8 @@ class SeekBarPreference(key: String) : Preference(key) { default = o.default step = o.step showTickMarks = o.showTickMarks - seekListener = o.seekListener + seekBeforeListener = o.seekBeforeListener + seekAfterListener = o.seekAfterListener formatter = o.formatter return this } @@ -112,10 +115,11 @@ class SeekBarPreference(key: String) : Preference(key) { if (done) { // Commit the last selected value commitInt(valueInternal) + seekAfterListener?.onSeekAfter(this@SeekBarPreference, v) } else { val next = calcValue(v) // Check if listener allows the value change - if (seekListener?.onSeek(this@SeekBarPreference, holder, next) != false) { + if (seekBeforeListener?.onSeekBefore(this@SeekBarPreference, next) != false) { // Update internal value valueInternal = next } else { @@ -136,20 +140,24 @@ class SeekBarPreference(key: String) : Preference(key) { private fun calcRaw(value: Int) = (value - min) / step private fun calcValue(raw: Int) = min + raw * step - fun interface OnSeekListener { + fun interface OnSeekAfterListener { + fun onSeekAfter( + preference: SeekBarPreference, + value: Int + ) + } + + fun interface OnSeekBeforeListener { /** * Notified when the [value][SeekBarPreference.value] of the connected [SeekBarPreference] changes. * This is called *before* the change gets persisted, which can be prevented by returning false. - * - * @param holder the [ViewHolder][PreferencesAdapter.ViewHolder] with the views of the Preference instance, * or null if the change didn't occur as part of a click event * @param value the new state * * @return true to commit the new slider value to [SharedPreferences][android.content.SharedPreferences] */ - fun onSeek( + fun onSeekBefore( preference: SeekBarPreference, - holder: PreferencesAdapter.ViewHolder?, value: Int ): Boolean } diff --git a/preference/src/main/res/layout/map_preference_widget_seekbar.xml b/preference/src/main/res/layout/map_preference_widget_seekbar.xml index 018aef399..f44bceca6 100644 --- a/preference/src/main/res/layout/map_preference_widget_seekbar.xml +++ b/preference/src/main/res/layout/map_preference_widget_seekbar.xml @@ -22,7 +22,7 @@ android:layout_height="wrap_content" android:layout_marginEnd="4dp" android:textColor="?colorAccent" - android:textSize="12sp" + android:textSize="15sp" app:layout_constraintBottom_toTopOf="@android:id/progress" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@android:id/progress"