mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
Polycentric fixes, missing sync files
This commit is contained in:
parent
fcbab10434
commit
7f26ac00b1
13 changed files with 196 additions and 49 deletions
|
@ -3,6 +3,7 @@ package com.futo.platformplayer.activities
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
|
@ -17,6 +18,7 @@ import com.futo.platformplayer.polycentric.PolycentricStorage
|
|||
import com.futo.platformplayer.setNavigationBarColorAndIcons
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.states.StatePolycentric
|
||||
import com.futo.platformplayer.views.LoaderView
|
||||
import com.futo.polycentric.core.ProcessHandle
|
||||
import com.futo.polycentric.core.Store
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -27,6 +29,7 @@ class PolycentricCreateProfileActivity : AppCompatActivity() {
|
|||
private lateinit var _buttonHelp: ImageButton;
|
||||
private lateinit var _profileName: EditText;
|
||||
private lateinit var _buttonCreate: LinearLayout;
|
||||
private lateinit var _loader: LoaderView;
|
||||
private val TAG = "PolycentricCreateProfileActivity";
|
||||
|
||||
private var _creating = false;
|
||||
|
@ -43,6 +46,7 @@ class PolycentricCreateProfileActivity : AppCompatActivity() {
|
|||
_buttonHelp = findViewById(R.id.button_help);
|
||||
_profileName = findViewById(R.id.edit_profile_name);
|
||||
_buttonCreate = findViewById(R.id.button_create_profile);
|
||||
_loader = findViewById(R.id.loader);
|
||||
findViewById<ImageButton>(R.id.button_back).setOnClickListener {
|
||||
finish();
|
||||
};
|
||||
|
@ -65,35 +69,49 @@ class PolycentricCreateProfileActivity : AppCompatActivity() {
|
|||
return@setOnClickListener;
|
||||
}
|
||||
|
||||
_profileName.isEnabled = false;
|
||||
_buttonCreate.visibility = View.GONE;
|
||||
_loader.start();
|
||||
_loader.visibility = View.VISIBLE;
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val processHandle: ProcessHandle;
|
||||
|
||||
try {
|
||||
processHandle = ProcessHandle.create();
|
||||
Store.instance.addProcessSecret(processHandle.processSecret);
|
||||
|
||||
try {
|
||||
PolycentricStorage.instance.addProcessSecret(processHandle.processSecret)
|
||||
processHandle = ProcessHandle.create();
|
||||
Store.instance.addProcessSecret(processHandle.processSecret);
|
||||
|
||||
try {
|
||||
PolycentricStorage.instance.addProcessSecret(processHandle.processSecret)
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to save process secret to secret storage.", e)
|
||||
}
|
||||
|
||||
processHandle.addServer(PolycentricCache.SERVER);
|
||||
processHandle.setUsername(username);
|
||||
StatePolycentric.instance.setProcessHandle(processHandle);
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to save process secret to secret storage.", e)
|
||||
Logger.e(TAG, getString(R.string.failed_to_create_profile), e);
|
||||
return@launch;
|
||||
} finally {
|
||||
_creating = false;
|
||||
}
|
||||
|
||||
processHandle.addServer(PolycentricCache.SERVER);
|
||||
processHandle.setUsername(username);
|
||||
StatePolycentric.instance.setProcessHandle(processHandle);
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, getString(R.string.failed_to_create_profile), e);
|
||||
return@launch;
|
||||
} finally {
|
||||
_creating = false;
|
||||
try {
|
||||
Logger.i(TAG, "Started backfill");
|
||||
processHandle.fullyBackfillServersAnnounceExceptions();
|
||||
Logger.i(TAG, "Finished backfill");
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, getString(R.string.failed_to_fully_backfill_servers), e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Logger.i(TAG, "Started backfill");
|
||||
processHandle.fullyBackfillServersAnnounceExceptions();
|
||||
Logger.i(TAG, "Finished backfill");
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, getString(R.string.failed_to_fully_backfill_servers), e);
|
||||
finally {
|
||||
withContext(Dispatchers.Main) {
|
||||
_profileName.isEnabled = true;
|
||||
_buttonCreate.visibility = View.VISIBLE;
|
||||
_loader.stop();
|
||||
_loader.visibility = View.GONE;
|
||||
}
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.os.Bundle
|
|||
import android.util.TypedValue
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ScrollView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.target.CustomTarget
|
||||
|
@ -28,6 +29,7 @@ class PolycentricHomeActivity : AppCompatActivity() {
|
|||
private lateinit var _buttonNewProfile: BigButton;
|
||||
private lateinit var _buttonImportProfile: BigButton;
|
||||
private lateinit var _layoutButtons: LinearLayout;
|
||||
private lateinit var _scroll: ScrollView;
|
||||
|
||||
override fun attachBaseContext(newBase: Context?) {
|
||||
super.attachBaseContext(StateApp.instance.getLocaleContext(newBase))
|
||||
|
@ -42,6 +44,7 @@ class PolycentricHomeActivity : AppCompatActivity() {
|
|||
_buttonNewProfile = findViewById(R.id.button_new_profile);
|
||||
_buttonImportProfile = findViewById(R.id.button_import_profile);
|
||||
_layoutButtons = findViewById(R.id.layout_buttons);
|
||||
_scroll = findViewById(R.id.scroll);
|
||||
findViewById<ImageButton>(R.id.button_back).setOnClickListener {
|
||||
finish();
|
||||
};
|
||||
|
@ -78,6 +81,7 @@ class PolycentricHomeActivity : AppCompatActivity() {
|
|||
|
||||
_layoutButtons.addView(profileButton, 0);
|
||||
}
|
||||
_scroll.invalidate();
|
||||
|
||||
_buttonHelp.setOnClickListener {
|
||||
startActivity(Intent(this, PolycentricWhyActivity::class.java));
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.futo.platformplayer.fullyBackfillServersAnnounceExceptions
|
|||
import com.futo.platformplayer.images.GlideHelper.Companion.crossfade
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.polycentric.PolycentricCache
|
||||
import com.futo.platformplayer.polycentric.PolycentricStorage
|
||||
import com.futo.platformplayer.selectBestImage
|
||||
import com.futo.platformplayer.setNavigationBarColorAndIcons
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
|
@ -33,6 +34,7 @@ import com.futo.platformplayer.views.buttons.BigButton
|
|||
import com.futo.platformplayer.views.overlays.LoaderOverlay
|
||||
import com.futo.polycentric.core.Store
|
||||
import com.futo.polycentric.core.SystemState
|
||||
import com.futo.polycentric.core.systemToURLInfoSystemLinkUrl
|
||||
import com.futo.polycentric.core.toBase64Url
|
||||
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
|
||||
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||
|
@ -47,6 +49,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
private lateinit var _buttonHelp: ImageButton;
|
||||
private lateinit var _editName: EditText;
|
||||
private lateinit var _buttonExport: BigButton;
|
||||
private lateinit var _buttonOpenHarborProfile: BigButton;
|
||||
private lateinit var _buttonLogout: BigButton;
|
||||
private lateinit var _buttonDelete: BigButton;
|
||||
private lateinit var _username: String;
|
||||
|
@ -68,6 +71,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
_imagePolycentric = findViewById(R.id.image_polycentric);
|
||||
_editName = findViewById(R.id.edit_profile_name);
|
||||
_buttonExport = findViewById(R.id.button_export);
|
||||
_buttonOpenHarborProfile = findViewById(R.id.button_open_harbor_profile);
|
||||
_buttonLogout = findViewById(R.id.button_logout);
|
||||
_buttonDelete = findViewById(R.id.button_delete);
|
||||
_loaderOverlay = findViewById(R.id.loader_overlay);
|
||||
|
@ -92,6 +96,16 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
startActivity(Intent(this, PolycentricBackupActivity::class.java));
|
||||
};
|
||||
|
||||
_buttonOpenHarborProfile.onClick.subscribe {
|
||||
val processHandle = StatePolycentric.instance.processHandle!!;
|
||||
processHandle?.let {
|
||||
val systemState = SystemState.fromStorageTypeSystemState(Store.instance.getSystemState(it.system));
|
||||
val url = it.system.systemToURLInfoSystemLinkUrl(systemState.servers.asIterable());
|
||||
val navUrl = "https://harbor.social/" + url.substring("polycentric://".length)
|
||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(navUrl)))
|
||||
}
|
||||
}
|
||||
|
||||
_buttonLogout.onClick.subscribe {
|
||||
StatePolycentric.instance.setProcessHandle(null);
|
||||
startActivity(Intent(this, PolycentricHomeActivity::class.java));
|
||||
|
@ -108,6 +122,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
|
|||
|
||||
StatePolycentric.instance.setProcessHandle(null);
|
||||
Store.instance.removeProcessSecret(processHandle.system);
|
||||
PolycentricStorage.instance.removeProcessSecret(processHandle.system);
|
||||
startActivity(Intent(this, PolycentricHomeActivity::class.java));
|
||||
finish();
|
||||
});
|
||||
|
|
|
@ -133,6 +133,10 @@ class ChannelAboutFragment : Fragment, IChannelTabFragment {
|
|||
Logger.w(TAG, "Failed to parse claim=$c", e)
|
||||
}
|
||||
}
|
||||
if(!map.containsKey("Harbor"))
|
||||
this.context?.let {
|
||||
map.set("Harbor", polycentricProfile.getHarborUrl(it));
|
||||
}
|
||||
|
||||
if (map.isNotEmpty())
|
||||
setLinks(map, if (polycentricProfile.systemState.username.isNotBlank()) polycentricProfile.systemState.username else _lastChannel?.name ?: "")
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package com.futo.platformplayer.fragment.mainactivity.main
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -12,6 +15,7 @@ import android.widget.ImageView
|
|||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.bumptech.glide.Glide
|
||||
|
@ -52,7 +56,9 @@ import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuOverlay
|
|||
import com.futo.platformplayer.views.subscriptions.SubscribeButton
|
||||
import com.futo.polycentric.core.OwnedClaim
|
||||
import com.futo.polycentric.core.PublicKey
|
||||
import com.futo.polycentric.core.Store
|
||||
import com.futo.polycentric.core.SystemState
|
||||
import com.futo.polycentric.core.systemToURLInfoSystemLinkUrl
|
||||
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
|
@ -64,7 +70,13 @@ import kotlinx.serialization.Serializable
|
|||
@Serializable
|
||||
data class PolycentricProfile(
|
||||
val system: PublicKey, val systemState: SystemState, val ownedClaims: List<OwnedClaim>
|
||||
)
|
||||
) {
|
||||
fun getHarborUrl(context: Context): String{
|
||||
val systemState = SystemState.fromStorageTypeSystemState(Store.instance.getSystemState(system));
|
||||
val url = system.systemToURLInfoSystemLinkUrl(systemState.servers.asIterable());
|
||||
return "https://harbor.social/" + url.substring("polycentric://".length);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelFragment : MainFragment() {
|
||||
override val isMainView: Boolean = true
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.futo.platformplayer.logging.Logger
|
|||
import com.futo.platformplayer.stores.FragmentedStorage
|
||||
import com.futo.platformplayer.stores.StringArrayStorage
|
||||
import com.futo.polycentric.core.ProcessSecret
|
||||
import com.futo.polycentric.core.PublicKey
|
||||
import com.futo.polycentric.core.base64ToByteArray
|
||||
import com.futo.polycentric.core.toBase64
|
||||
import userpackage.Protocol
|
||||
|
@ -29,6 +30,18 @@ class PolycentricStorage {
|
|||
return processSecrets
|
||||
}
|
||||
|
||||
fun removeProcessSecret(publicKey: PublicKey) {
|
||||
for(p in _processSecrets.getAllValues()){
|
||||
try {
|
||||
val key = ProcessSecret.fromProto(Protocol.StorageTypeProcessSecret.parseFrom(GEncryptionProviderV1.instance.decrypt(p.base64ToByteArray())));
|
||||
if(key.system.publicKey.equals(publicKey))
|
||||
_processSecrets.remove(p);
|
||||
} catch (e: Throwable) {
|
||||
Logger.i(TAG, "Failed to decrypt process secret", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = "PolycentricStorage";
|
||||
private var _instance : PolycentricStorage? = null;
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package com.futo.platformplayer.sync.internal
|
||||
|
||||
class GJSyncOpcodes {
|
||||
companion object {
|
||||
val sendToDevices: UByte = 101.toUByte();
|
||||
|
||||
val syncExport: UByte = 201.toUByte();
|
||||
val syncSubscriptions: UByte = 202.toUByte();
|
||||
val syncHistory: UByte = 203.toUByte();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.futo.platformplayer.sync.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class SendToDevicePackage(
|
||||
var url: String,
|
||||
var position: Int = 0
|
||||
)
|
|
@ -0,0 +1,12 @@
|
|||
package com.futo.platformplayer.sync.models
|
||||
|
||||
import com.futo.platformplayer.models.Subscription
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.Dictionary
|
||||
|
||||
@Serializable
|
||||
class SyncSubscriptionsPackage(
|
||||
var subscriptions: List<Subscription>,
|
||||
var subscriptionRemovals: Map<String, Long>
|
||||
)
|
|
@ -42,11 +42,17 @@ class PlatformLinkView : LinearLayout {
|
|||
}
|
||||
|
||||
fun setPlatform(name: String, url: String) {
|
||||
val icon = StatePlatform.instance.getClientOrNullByUrl(url)?.icon;
|
||||
if (icon != null) {
|
||||
icon.setImageView(_imagePlatform, R.drawable.ic_web_white);
|
||||
} else {
|
||||
_imagePlatform.setImageResource(R.drawable.ic_web_white);
|
||||
|
||||
if(url.startsWith("https://harbor.social")) {
|
||||
_imagePlatform.setImageResource(R.drawable.neopass);
|
||||
}
|
||||
else {
|
||||
val icon = StatePlatform.instance.getClientOrNullByUrl(url)?.icon;
|
||||
if (icon != null) {
|
||||
icon.setImageView(_imagePlatform, R.drawable.ic_web_white);
|
||||
} else {
|
||||
_imagePlatform.setImageResource(R.drawable.ic_web_white);
|
||||
}
|
||||
}
|
||||
|
||||
_textName.text = name;
|
||||
|
|
|
@ -92,5 +92,13 @@
|
|||
android:textSize="16dp"
|
||||
android:text="@string/create_profile" />
|
||||
</LinearLayout>
|
||||
<com.futo.platformplayer.views.LoaderView
|
||||
android:id="@+id/loader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/button_create_profile"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -45,33 +45,43 @@
|
|||
app:layout_constraintLeft_toLeftOf="@id/image_polycentric"
|
||||
app:layout_constraintRight_toRightOf="@id/image_polycentric" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_buttons"
|
||||
<ScrollView
|
||||
android:id="@+id/scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="0px"
|
||||
android:layout_marginTop="10dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginTop="30dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_polycentric"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent">
|
||||
app:layout_constraintTop_toBottomOf="@id/text_polycentric">
|
||||
|
||||
<com.futo.platformplayer.views.buttons.BigButton
|
||||
android:id="@+id/button_new_profile"
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:buttonText="@string/new_profile"
|
||||
app:buttonSubText="@string/generate_a_new_identity"
|
||||
app:buttonIcon="@drawable/ic_person_add" />
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.futo.platformplayer.views.buttons.BigButton
|
||||
android:id="@+id/button_import_profile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:buttonText="@string/import_existing_profile"
|
||||
app:buttonSubText="@string/use_an_existing_identity"
|
||||
app:buttonIcon="@drawable/ic_arrow_downward"
|
||||
android:layout_marginTop="8dp" />
|
||||
</LinearLayout>
|
||||
<com.futo.platformplayer.views.buttons.BigButton
|
||||
android:id="@+id/button_new_profile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:buttonIcon="@drawable/ic_person_add"
|
||||
app:buttonSubText="@string/generate_a_new_identity"
|
||||
app:buttonText="@string/new_profile" />
|
||||
|
||||
<com.futo.platformplayer.views.buttons.BigButton
|
||||
android:id="@+id/button_import_profile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:buttonIcon="@drawable/ic_arrow_downward"
|
||||
app:buttonSubText="@string/use_an_existing_identity"
|
||||
app:buttonText="@string/import_existing_profile" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -65,6 +65,22 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/edit_profile_name"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
<TextView
|
||||
android:id="@+id/text_cta"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:text="Further customize your profile, make platform claims, and other creator-specific features in the Harbor app.\n\nYou can export this profile to Harbor using the Export button."
|
||||
android:textSize="12dp"
|
||||
android:paddingLeft="20dp"
|
||||
android:paddingRight="20dp"
|
||||
android:textAlignment="center"
|
||||
android:ellipsize="middle"
|
||||
android:textColor="@color/gray_ac"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_system"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_buttons"
|
||||
|
@ -75,9 +91,18 @@
|
|||
android:layout_marginEnd="20dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/edit_profile_name"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_cta"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<com.futo.platformplayer.views.buttons.BigButton
|
||||
android:id="@+id/button_open_harbor_profile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:buttonText="Harbor Profile"
|
||||
app:buttonSubText="See your Harbor profile in a browser"
|
||||
app:buttonIcon="@drawable/ic_export"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
<com.futo.platformplayer.views.buttons.BigButton
|
||||
android:id="@+id/button_export"
|
||||
android:layout_width="match_parent"
|
||||
|
|
Loading…
Add table
Reference in a new issue